【问题标题】:wxpython. Need assistance with confusing errorwxpython。需要帮助解决令人困惑的错误
【发布时间】:2014-06-24 15:17:13
【问题描述】:

此代码适用于另一台计算机上的其他人,但它似乎不适用于我。我正在使用 python 2.7.7。它对另外两个人效果很好,但它似乎不喜欢我或我的电脑,因为每当我运行它时,它都会给我一条错误消息。大家觉得呢?

Traceback (most recent call last):
  File "C:\Python27\python projects\client with gui.py", line 43, in <module>
    frame = WindowFrame(None, 'ChatClient')
  File "C:\Python27\python projects\client with gui.py", line 10, in __init__
    self.dc = wx.PaintDC(self.panel)  # <<< This was changed
  File "C:\Python27\python projects\lib\site-packages\wx-3.0-msw\wx\_gdi.py", line 5215, in __init__
    _gdi_.PaintDC_swiginit(self,_gdi_.new_PaintDC(*args, **kwargs))
PyAssertionError: C++ assertion "Assert failure" failed at ..\..\src\msw\dcclient.cpp(277) in wxPaintDCImpl::wxPaintDCImpl(): wxPaintDCImpl may be created only in EVT_PAINT handler!





import socket
import wx

class WindowFrame(wx.Frame):
    def __init__(self, parent, title):
        wx.Frame.__init__(self, parent, title = title, size=(500, 400))
        self.panel=wx.Panel(self)
        self.panel.SetBackgroundColour("#0B3861")
        self.control = wx.TextCtrl(self.panel, style = wx.TE_MULTILINE, size =(410, 28), pos=(0,329))
        self.dc = wx.PaintDC(self.panel)  # <<< This was changed
        # Sets up the socket connection
        self.s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        host = "127.0.0.1"
        port = 6667
        self.s.connect((host,port))

        # creates send button and binds to event
        sendbutton=wx.Button(self.panel, label ="Send", pos =(414,325), size=(65,35))
        self.panel.Bind(wx.EVT_PAINT, self.OnPaint)
        self.Bind(wx.EVT_BUTTON, self.SendPress, sendbutton )

        self.Centre()
        self.Show()

        #Draws white rectangle
    def OnPaint(self, event):
        self.dc.SetPen(wx.Pen('black'))
        self.dc.SetBrush(wx.Brush('white'))
        self.shapeRectangle=self.dc.DrawRectangle(20, 20, 444, 280)
        self.Show(True)


        # Sets the function of the send button
    def SendPress(self, event):
        self.sent = self.control.GetValue()
        self.s.send(self.sent)
        self.control.Clear()
        self.dc.DrawText(self.sent, 0, 300 )
        self.s.close()

if __name__=="__main__":
    app = wx.App(False)
    frame = WindowFrame(None, 'ChatClient')
    app.MainLoop()

【问题讨论】:

    标签: python sockets wxpython


    【解决方案1】:

    运行此代码时,我遇到了与您相同的错误。查看下面链接的文档“如果应用程序希望在 EVT_PAINT 事件处理程序中在窗口的客户区域上绘画,则必须构造 wx.PaintDC。”

    http://www.wxpython.org/docs/api/wx.PaintDC-class.html

    您是否考虑将其更改为客户端 DC? "如果应用程序希望从 EVT_PAINT 事件之外在窗口的客户区域上绘画,则必须构造 wx.ClientDC"

    http://www.wxpython.org/docs/api/wx.ClientDC-class.html

    通常我认为您会在绑定到 EVT_PAINT 事件的方法中创建 PaintDC,我检查了一些代码示例,当我希望从外部查找属性或影响画布时,我通常似乎使用 ClientDC画法。

    为此,我会改变:

    self.dc = wx.PaintDC(self.panel)
    

    到:

    self.dc = wx.ClientDC(self.panel)
    

    这是您的代码的完整修改版本,使用原始 PaintDC 执行我认为您正在尝试执行的操作。

    import socket
    import wx
    
    class WindowFrame(wx.Frame):
        def __init__(self, parent, title):
            wx.Frame.__init__(self, parent, title = title, size=(500, 400))
            self.panel=wx.Panel(self)
            self.panel.SetBackgroundColour("#0B3861")
            self.control = wx.TextCtrl(self.panel, style = wx.TE_MULTILINE, size =(410, 28), pos=(0,329))
            self.textLog = []
            # Sets up the socket connection
            self.s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            host = "127.0.0.1"
            port = 6667
            self.s.connect((host,port))
    
            # creates send button and binds to event
            sendbutton=wx.Button(self.panel, label ="Send", pos =(414,325), size=(65,35))
            self.panel.Bind(wx.EVT_PAINT, self.OnPaint)
            self.Bind(wx.EVT_BUTTON, self.SendPress, sendbutton )
    
            self.Centre()
            self.Show()
    
            #Draws white rectangle
        def OnPaint(self, event):
            dc = wx.PaintDC(self.panel) 
            dc.SetPen(wx.Pen('black'))
            dc.SetBrush(wx.Brush('white'))
            dc.Clear()
            x, y = 20,20
            self.shapeRectangle=dc.DrawRectangle(x, y, 444, 280)
            fnt = dc.GetFont()        
            for i,line in enumerate(self.textLog):
                if i%2:
                    dc.SetTextForeground(wx.RED)
                else:
                    dc.SetTextForeground(wx.BLUE)
            dc.SetFont(fnt)
                dc.DrawText(line, x, y)
                y += dc.GetCharHeight()
    
            # Sets the function of the send button
        def SendPress(self, event):
            self.sent = self.control.GetValue()
            self.s.send(self.sent)
            self.control.Clear()
            self.textLog.append(self.sent)
            self.panel.Refresh()
            self.s.close()
    
    if __name__=="__main__":
        app = wx.App(False)
        frame = WindowFrame(None, 'ChatClient')
        app.MainLoop()
    

    【讨论】:

    • 你能发一个例子吗
    • 对不起,我不清楚,我把:self.dc = wx.PaintDC(self.panel) 改为 self.dc = wx.ClientDC(self.panel)
    • 它有效,但我希望它打印在我绘制的矩形上,当我将 self.dc =wx.ClientDC(self.panel) 转换为 self.dc =wx.ClientDC(self.shapeRectangle) 时给了我这个错误 Traceback (最近一次调用最后): File "C:\Python27\python projects\client with gui.py", line 43, in frame = WindowFrame(None, 'ChatClient') File "C: \Python27\python projects\client with gui.py", line 10, init self.dc = wx.ClientDC(self.shapeRectangle) #
    • 我明白了,这里有几个选项取决于您想要做什么,您想显示所有过去发送的消息还是只显示最近的消息?如果您更改 self.do.DrawText 坐标,您可以将此文本放在矩形上,但是当重新绘制矩形时它将被替换。我怀疑你想要的是将文本添加到列表中,然后让画布重新绘制自身打印所有过去的消息,这是正确的吗?
    • 我已经编辑了我的回复并添加了一个版本,它可以执行我认为您正在尝试做的事情,如果这不正确,请告诉我。我在没有套接字代码的情况下对其进行了测试,因为我对套接字等一无所知。
    【解决方案2】:

    这个例子有不少问题:

    • 绝对定位而不是 sizers
    • 绘图时不自动换行(通常自己渲染文本是个坏主意)
    • 区分发送/接收的奇怪方法 (i%2 ???)

    在这种情况下,使用适当的控件来显示彩色文本会更合适。插入您认为合适的发送/接收机制

    import wx
    from wx.stc import StyledTextCtrl
    
    class WindowFrame(wx.Frame):
        def __init__(self, parent, title):
            wx.Frame.__init__(self, parent, title = title, size=(500, 400))
    
            self.panel = wx.Panel(self)
            self.panel.SetBackgroundColour("#0B3861")
            self.stc = StyledTextCtrl(self.panel, -1)
            self.control = wx.TextCtrl(self.panel, style = wx.TE_MULTILINE)
            sendbutton=wx.Button(self.panel, label ="Send")
            recvbutton=wx.Button(self.panel, label ="Receive")
    
            sendbutton.Bind(wx.EVT_BUTTON, self.SendPress)
            recvbutton.Bind(wx.EVT_BUTTON, self.RecvPress)
    
            szmain = wx.BoxSizer(wx.VERTICAL)
            szmain.Add(self.stc, 1, wx.EXPAND|wx.ALL, 4)
            szsub = wx.BoxSizer(wx.HORIZONTAL)
            szsub.Add(self.control, 1, wx.EXPAND|wx.ALL, 4)
            szsub.Add(sendbutton, 0, wx.EXPAND|wx.ALL, 4)
            szsub.Add(recvbutton, 0, wx.EXPAND|wx.ALL, 4)
            szmain.Add(szsub, 0, wx.EXPAND|wx.ALL, 0)
    
            self.panel.SetSizer(szmain)
            self.Centre()
            self.Show()
    
            # define styles for stc, 0 red fore color, 1 blue fore color
            self.stc.StyleSetSpec(0, "fore:#FF0000")
            self.stc.StyleSetSpec(1, "fore:#0000FF")
            self.stc.SetWrapMode(True) #autowrap
    
        def add_text(self, text, style):
            curpos = self.stc.GetCurrentPos()
            self.stc.AddText(text)
            self.stc.AddText('\r\n')
            newpos = self.stc.GetCurrentPos()
            delta = newpos-curpos
    
            # consult the Scintilla doc (stc is based on it) to understand how styling works
            # http://www.scintilla.org/ScintillaDoc.html#Styling
            self.stc.StartStyling(curpos, 31) # mask 31 allows setting of styles
            self.stc.SetStyling(delta, style)
            self.stc.ScrollToEnd() # keep last line visible
    
            # Sets the function of the send button
        def SendPress(self, event):
            self.add_text(self._get_text(), 0)
    
            # Sets the function of the recv button
        def RecvPress(self, event):
            self.add_text(self._get_text(), 1)
    
        def _get_text(self):
            text = self.control.GetValue()
            self.control.Clear()
            return text
    
    
    if __name__=="__main__":
        app = wx.App(False)
        frame = WindowFrame(None, 'ChatClient')
        app.MainLoop()
    

    查看 wxPython 演示如何使用StyledTextControl(基于 Scintilla)。最后但并非最不重要的一点是它让我学习了STC

    【讨论】:

    • StyledTextControl 看起来不错,我今天花了一些时间研究 Scintilla,感谢您引起我的注意!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-09
    • 1970-01-01
    • 2021-09-10
    • 2021-12-11
    • 1970-01-01
    相关资源
    最近更新 更多