How to wxPanel.Refresh?

核能气质少年 提交于 2020-01-25 10:14:03

问题


I have a background in C# (.NET2.0) desktop application development and for the last years C for microcontrollers. Now for GUI applications on Linux and Windows, I'm learning python through wxPython.

I'm on Linux Mint 19 Mate, Python 2.7, wxPython 3.0, wxGlade 0.8.0-1, Stani's Python Editor 0.8.4.

wxGlade created some GUI code and I coded a bit of event handling into it. My problem is that my code calls wxPanel.Refresh() on a mouse event but the panel doesn't get refreshed. I know that the drawing code works because it does when the window is buried under another one and comes back to the front. Therefore I tried to call wxPanel.Hide() and wxPanel.Show instead of refreshing and that works.

But refreshing should work on its own. I have a bad feeling of using hide-and-show for dragging stuff on the panel.

What am I missing about wxPanel.Refresh()?

I also tried wxPanel.Update(), but to no avail. There are no errors on the console at runtime. Here's the complete code. Interesting part is the commented-out line 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()

回答1:


It appears that you are expecting to handle the mouse and paint events for self.DrawPanel, but you are actually binding the event handlers to the frame instead. This has consequences. For example, in your paint event handler self is the frame, not the DrawPanel so the dc you create will do its drawing on the frame's client area instead of the panel. The panel will likely be getting in the way of seeing what's on the frame, and blocking some of the mouse events, etc.

A better design would be to make the draw panel be a separate class, and move the related event bindings and event handlers to that class. Then the frame will just need to create an instance of that new class instead of a base wx.Panel.



来源:https://stackoverflow.com/questions/59689325/how-to-wxpanel-refresh

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!