我具有C#(.NET2.0)桌面应用程序开发的背景,并且最近几年具有微控制器C的背景。现在,对于Linux和Windows上的GUI应用程序,我正在通过wxPython学习python。
我正在使用Linux Mint 19 Mate,Python 2.7,wxPython 3.0,wxGlade 0.8.0-1,Stani的Python编辑器0.8.4。
wxGlade创建了一些GUI代码,我在其中编写了一些事件处理代码。我的问题是我的代码在发生鼠标事件时调用wxPanel.Refresh(),但是面板没有刷新。我知道绘图代码有效,因为当窗口被埋在另一个窗口之下并返回到最前面时,该代码才起作用。因此,我尝试调用wxPanel.Hide()和wxPanel.Show而不是刷新,并且有效。
但是刷新应该自己进行。我不喜欢使用“隐藏和显示”在面板上拖动内容。
关于wxPanel.Refresh()我缺少什么?
我也尝试过wxPanel.Update(),但无济于事。运行时控制台上没有错误。这是完整的代码。有趣的是注释掉的第78行。
# -*- coding: UTF-8 -*-
#
# generated by wxGlade 0.8.0 on Thu Jan 9 14:00:42 2020
#
import wx
# begin wxGlade: dependencies
# end wxGlade
# begin wxGlade: extracode
# end wxGlade
class MyFrame(wx.Frame):
def __init__(self, *args, **kwds):
# begin wxGlade: MyFrame.__init__
kwds["style"] = kwds.get("style", 0) | wx.DEFAULT_FRAME_STYLE
wx.Frame.__init__(self, *args, **kwds)
self.SetSize((729, 521))
# Menu Bar
self.MainMenuBar = wx.MenuBar()
wxglade_tmp_menu = wx.Menu()
wxglade_tmp_menu.Append(wx.ID_ANY, "Open", "")
wxglade_tmp_menu.Append(wx.ID_ANY, "Close", "")
wxglade_tmp_menu.AppendSeparator()
wxglade_tmp_menu.Append(wx.ID_ANY, "Exit", "")
self.MainMenuBar.Append(wxglade_tmp_menu, "File")
wxglade_tmp_menu = wx.Menu()
wxglade_tmp_menu.Append(wx.ID_ANY, "Preferences", "")
self.MainMenuBar.Append(wxglade_tmp_menu, "Edit")
wxglade_tmp_menu = wx.Menu()
wxglade_tmp_menu.Append(wx.ID_ANY, "About", "")
self.MainMenuBar.Append(wxglade_tmp_menu, "?")
self.SetMenuBar(self.MainMenuBar)
# Menu Bar end
self.DrawPanel = wx.Panel(self, wx.ID_ANY)
self.Bind(wx.EVT_LEFT_DOWN, self.DrawPanel_HandleLEFT_DOWN)
self.Bind(wx.EVT_LEFT_UP, self.DrawPanel_HandleLEFT_UP)
self.Bind(wx.EVT_MOTION, self.DrawPanel_HandleMOTION)
self.Bind(wx.EVT_PAINT, self.DrawPanel_HandlePAINT)
self.__set_properties()
self.__do_layout()
# end wxGlade
self.DrawPanel_LmbDown = False
self.coords = []
def __set_properties(self):
# begin wxGlade: MyFrame.__set_properties
self.SetTitle("frame")
# end wxGlade
def __do_layout(self):
# begin wxGlade: MyFrame.__do_layout
MainSizer = wx.BoxSizer(wx.VERTICAL)
Statusbar = wx.BoxSizer(wx.HORIZONTAL)
MainSizer.Add(self.DrawPanel, 0, wx.EXPAND, 0)
Statusbar.Add((0, 0), 0, 0, 0)
Statusbar.Add((0, 0), 0, 0, 0)
Statusbar.Add((0, 0), 0, 0, 0)
Statusbar.Add((0, 0), 0, 0, 0)
MainSizer.Add(Statusbar, 0, 0, 0)
self.SetSizer(MainSizer)
self.Layout()
# end wxGlade
def DrawPanel_HandleLEFT_DOWN(self, event):
self.DrawPanel_LmbDown = True
coord = event.GetPosition()
print("Lmb Down at ", coord[0], ";", coord[1])
if(coord not in self.coords):
self.coords.append(coord)
print(self.coords)
# self.DrawPanel.Refresh() # Todo: Find out why Refresh() doesn't work and
self.DrawPanel.Hide() # A combination of Hide() and
self.DrawPanel.Show() # Show() must do the trick.
event.Skip()
def DrawPanel_HandleLEFT_UP(self, event):
self.DrawPanel_LmbDown = False
coord = event.GetPosition()
print("Lmb Up at ", coord[0], ";", coord[1])
event.Skip()
def DrawPanel_HandleMOTION(self, event):
if(self.DrawPanel_LmbDown):
coord = event.GetPosition()
print("Moving with Lmb Down to ", coord[0], ";", coord[1])
event.Skip()
def DrawPanel_HandlePAINT(self, event):
dc = wx.PaintDC(self)
brush = wx.Brush("white")
dc.SetBackground(brush)
dc.Clear()
pen = wx.Pen("red")
dc.SetPen(pen)
for coord in self.coords:
dc.DrawLine(coord[0] - 2, coord[1] - 2, coord[0] + 2, coord[1] + 2)
dc.DrawLine(coord[0] - 2, coord[1] + 2, coord[0] + 2, coord[1] - 2)
event.Skip()
# end of class MyFrame
class MyApp(wx.App):
def OnInit(self):
self.MainFrame = MyFrame(None, wx.ID_ANY, "")
self.SetTopWindow(self.MainFrame)
self.MainFrame.Show()
return True
# end of class MyApp
if __name__ == "__main__":
app = MyApp(0)
app.MainLoop()
看来您希望处理self.DrawPanel
的鼠标和绘画事件,但实际上是将事件处理程序绑定到框架。这有后果。例如,在绘画事件处理程序中,self
是框架,而不是DrawPanel
,因此您创建的DC将在框架的工作区而不是面板上进行绘制。面板可能会妨碍查看框架上的内容,并阻止某些鼠标事件,等等。
更好的设计是使绘图面板成为一个单独的类,并将相关的事件绑定和事件处理程序移到该类。然后,框架仅需要创建该新类的实例,而不是基础wx.Panel
。