UltimateListCtrl中的小部件窗口无法调整大小/刷新

1 投票
1 回答
547 浏览
提问于 2025-05-10 21:21

我的目标是创建一个 ULC,里面有一列 TextCtrl,用户输入时行高会动态调整。如果有更好的方法,请告诉我。

这是我尝试过的:

ExpandoTextCtrl 正是我想要的。我有一个可以正常工作的例子,所以我知道我能正确实现它,我想要的是一列这样的控件:

import wx
import sys
import wx.lib.expando as ex

class TestPanel(wx.Panel):
    def __init__(self, parent):
        wx.Panel.__init__(self, parent)
        text = "\"I\'ll Be Missing You\" is a song recorded by American rapper Puff Daddy and American singer Faith Evans, featuring R&B group 112, in memory of fellow Bad Boy Records artist Christopher \"The Notorious B.I.G.\" Wallace, who was gunned down on March 9, 1997. --Wikipedia"
        self.edit_text = ex.ExpandoTextCtrl(self, value = text, size = (200,50))
        self.edit_text.SetMaxHeight(sys.maxint)

class TestFrame(wx.Frame):
    def __init__(self):
        wx.Frame.__init__(self, None, title="expando Demo")
        panel = TestPanel(self)
        self.Show()
#----------------------------------------------------------------------
if __name__ == "__main__":
    app = wx.App(False)
    frame = TestFrame()
    app.MainLoop()

当你添加或删除行时,它会实时调整高度,能够根据任何字符变化(不仅仅是换行符或简单的东西)。

但是如果我把它放到 UltimateListCtrl 的一个单元格里,它的大小是固定的,大约是列宽和可见的两行文本,所以它根本无法显示完整的文本,而且也不会自动调整大小。

我在其他类型的 Window 中也遇到同样的问题。我写了一个 button,点击时它会改变大小。我的这段代码(如果你想我可以发出来,但感觉有点多余)在自己的面板或与其他控件一起放在 Sizer 中运行得很好,但在 ULC 中,它只会以原始大小实例化,调用 button.SetSize() 后也不会改变。

我查过关于 ULC 的错误报告,但没有看到相关的未解决问题。我尝试过调用 ULCRefresh()Update()Show(False/True) 方法,以及在父 PanelFrame 上做同样的操作,但都没有成功。

这是我的代码,基于网上一个常见的 ULC 示例:

import wx
import sys
from wx.lib.agw import ultimatelistctrl as ULC
import wx.lib.expando as ex

class TestPanel(wx.Panel):
    def __init__(self, parent):
        wx.Panel.__init__(self, parent)
        self.sizes = self.size_gen()
        font = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT)
        boldfont = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT)
        boldfont.SetWeight(wx.BOLD)
        boldfont.SetPointSize(12)

        self.ultimateList = ULC.UltimateListCtrl(self, agwStyle = wx.LC_REPORT
                                         | wx.LC_VRULES
                                         | wx.LC_HRULES
                                         | ULC.ULC_HAS_VARIABLE_ROW_HEIGHT)

        info = ULC.UltimateListItem()
        info._mask = wx.LIST_MASK_TEXT | wx.LIST_MASK_IMAGE | wx.LIST_MASK_FORMAT | ULC.ULC_MASK_CHECK
        info._image = []
        info._format = 0
        info._kind = 1
        info._text = "Artist Name"
        self.ultimateList.InsertColumnInfo(0, info)

        info = ULC.UltimateListItem()
        info._format = wx.LIST_FORMAT_RIGHT
        info._mask = wx.LIST_MASK_TEXT | wx.LIST_MASK_IMAGE | wx.LIST_MASK_FORMAT | ULC.ULC_MASK_FONT
        info._image = []
        info._text = "Title"
        info._font = boldfont
        self.ultimateList.InsertColumnInfo(1, info)

        info = ULC.UltimateListItem()
        info._mask = wx.LIST_MASK_TEXT | wx.LIST_MASK_IMAGE | wx.LIST_MASK_FORMAT
        info._format = 0
        info._text = "Genre"
        info._font = font
        info._image = []
        self.ultimateList.InsertColumnInfo(2, info)

        self.ultimateList.InsertStringItem(0, "Newsboys")
        self.ultimateList.SetStringItem(0, 1, "Go")
        self.ultimateList.SetStringItem(0, 2, "Rock")

        text = "\"I\'ll Be Missing You\" is a song recorded by American rapper Puff Daddy and American singer Faith Evans, featuring R&B group 112, in memory of fellow Bad Boy Records artist Christopher \"The Notorious B.I.G.\" Wallace, who was gunned down on March 9, 1997. --Wikipedia"
        self.ultimateList.InsertStringItem(1, "Puffy")
        edit_text = ex.ExpandoTextCtrl(self.ultimateList, value = text, size=(200,50))
        edit_text.SetMaxHeight(sys.maxint)
        self.ultimateList.SetItemWindow(1, col=1, wnd=edit_text, expand=True)
        self.ultimateList.SetStringItem(1, 2, "Pop")

        self.ultimateList.InsertStringItem(2, "Family Force 5")
        self.button = wx.Button(self.ultimateList, label='button', size =(200,200))
        self.button.Bind(wx.EVT_BUTTON, self.on_button)
        self.ultimateList.SetItemWindow(2, 1, self.button, expand=True)
        #self.ultimateList.SetStringItem(2, 1, "III")
        self.ultimateList.SetStringItem(2, 2, "Crunk")

        self.ultimateList.SetColumnWidth(0, 150)
        self.ultimateList.SetColumnWidth(1, 200)
        self.ultimateList.SetColumnWidth(2, 100)

        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(self.ultimateList, 1, wx.EXPAND)
        self.SetSizer(sizer)

    def on_button(self, event):
        self.button.SetSize(self.sizes.next())

    def size_gen(self):
        sizes = [(150,200),(200,200),(80,80)]
        index = 0
        while True:
            yield sizes[index]
            index = index + 1
            if index > 2:
                index = 0

########################################################################
class TestFrame(wx.Frame):
    def __init__(self):
        wx.Frame.__init__(self, None, title="MvP UltimateListCtrl Demo")
        panel = TestPanel(self)
        self.Show()

#----------------------------------------------------------------------
if __name__ == "__main__":
    app = wx.App(False)
    frame = TestFrame()
    app.MainLoop()

编辑

我现在尝试了几种不同的方法。我去掉了所有的列格式,只用简单的 list.InsertColumn(index, label) 调用替换了那三个块。我做的最有用的事情是从 ULC.SetItemWindow() 调用中去掉了 expand=True。这似乎让按钮的宽度(但不是高度)恢复了控制。因为它的初始大小是 150Wx200H,当我调用 next 并改变为 200x200 时,按钮会溢出到右边的下一个单元格。当我再次调用 next,要求 80x80 的大小时,按钮缩小到 150x200,无法设置得比它的初始大小更小。

如果我把按钮初始化得比我需要的尺寸小,比如 50x30,那么我可以在两个维度上正确设置所有的大小(80,80;200,200),但按钮会溢出到右边和下面的邻居。

在这里输入图片描述 在这里输入图片描述

你可以看到列表没有刷新任何行。你也可以看到控件保持了它原来的左上角位置(也许这是正确的,但我觉得不太对)。

如果我在 on_button 中添加 list.Refresh/DoLayout/Layout/Update,也没有效果。

拖动或重新定位窗口(顶层 Frame)也没有效果。ULC.SendSizeEvent 也没有效果。

下一个想法

我还尝试删除整行并插入一个新大小的按钮,像这样:

def on_button(self,event):

    new_size = self.sizes.next()
    print new_size
    l = self.ultimateList
    label = l.GetItemWindow(1, 1).GetLabel()
    l.DeleteItem(1)
    self.button = wx.Button(self.ultimateList, label=label, size=new_size)
    self.button.Bind(wx.EVT_BUTTON, self.on_button)
    l.InsertStringItem(1, 'Family Farce 5')
    l.SetItemWindow(1,1,self.button)
    l.SetStringItem(1,2,'Crunk')

我觉得这不是一个好的策略,因为在每次按键时销毁和重建一个 edit_text 听起来会有很多问题,但公平地说我还没有尝试过。

无论如何,使用按钮时我可以调用它并正确调整大小。问题是 ULC 不会根据新高度或甚至初始高度重新绘制后续行,而是使用默认的行高度。它确实会以正确的高度绘制带有按钮的重建行。

在这里输入图片描述

这次(删除行并添加新行)我注意到重新调整窗口(顶层 Frame)强制了重绘,所以我在 on_button 中添加了 SendSizeEvent,现在按钮工作得很好。

在这里输入图片描述

显然,我已经找到了如何用新大小替换一行的方法。

所以问题仍然是关于 WindowULC 中,我可以动态调整控件的大小,但我该如何强制 ULC 在调整控件大小后重新绘制自己?

换句话说:为什么 SendSizeEvent 在插入新项目到列表后会强制刷新,但在修改现有项目后却不会? 如果我知道该扩展哪个方法或属性,我可以对 ULC 进行子类化。我尝试查看源代码,但搞不清楚。

相关文章:

  • 暂无相关问题
暂无标签

1 个回答

0

首先,ULC(UltimateListCtrl)只会计算行高一次。如果在绘制一行的时候,行高已经存在了,它就不会再计算一次了。

另外,当你添加一个新窗口时,窗口的大小会被写入到行对象中。这一过程只会发生一次,之后就不会再做了,也无法通过任何手段手动触发。

不过:

如果你按照下面的方式调整UltimateListCtrl,它就能正常工作。

UltimateListItemData类中的GetWindowSize函数(第2863行):

def GetWindowSize(self):
    """ Returns the associated window size. """
    wnd = self._wnd
    if wnd.GetSizer():      # the window is a complex one hold by a sizer
        size = wnd.GetBestSize()
    else:                   # simple window, without sizers
        size = wnd.GetSize()
    print(size)
    return size

在你的代码中,你需要使旧的行高失效,这样它才能重新计算:

def on_button(self, event):
    self.button.SetSize(self.sizes.next())
    self.ultimateList._mainWin.ResetLineDimensions(True)
    self.ultimateList._mainWin.RecalculatePositions()

请注意,这样做会修改ULC并访问一些私有变量。

Lokla

撰写回答