【问题标题】:What is the code structure when integrating a GUI with wxpython将 GUI 与 wxpython 集成时的代码结构是什么
【发布时间】:2021-10-08 15:27:10
【问题描述】:

我有一个关于代码结构的可能非常简单的问题

我编写了一个连接到 Web 套接字以检索数据然后进行大量计算的应用程序

基本上,websocket 在一个线程中打开,主循环中的繁重计算随后是控制台显示。需要注意的是,我可能不得不使用多处理将代码拆分到多个内核上。

我现在正在尝试在 wxpython 中显示。我制作了一个带有 GUI 的单独项目,它本身可以正常工作。主循环是:

def main():
    app = wx.App()
    ex = MainWindows(rows)
    app.MainLoop()

if __name__ == '__main__':
    main()

MainWindows 函数就是这样开始的:

    class MainWindows(wx.Frame):
    
        def __init__(self, *args, **kwargs):
            super(MainWindows, self).__init__(data=rows, *args, **kwargs)
    
            self.InitUI(rows)
    
        def InitUI(self, rows):
            # Set Frame options
            self.SetSize((800, 600))
            self.SetTitle('Title')
            self.Centre()
...

现在想知道如何完成后台繁重的计算以及如何将参数传递给我的 MainWindows 类。 我试过调查 *args 和 **kwargs 但没有成功。总是编译错误说我的班级不参加更多参数。

所以我的问题是:

  1. 集成后台计算、websocket 处理等的最佳方式是什么(我认为放入线程是最好的)

  2. 如何与我的 GUI 共享数据(参数传递)

  3. 如何定期(例如每秒)刷新小部件以使用在单独线程中处理的 websocket 中的日期进行更新(实际上我正在尝试在 ListCtrl 小部件中显示我的 websocked 处理的内容并希望在实时

我想在其中显示我的数据的完整测试 GUI 代码(请参阅订单选项卡)。变量 rows 是来自 websocket 数据的后台计算的数据示例:

Version_Major = 3
Version_Minor = 0
Version_patch = 0

#########
# IMPORTS
#########
import wx, sys
import matplotlib
matplotlib.use('WXAgg')
from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as FigureCanvas
from matplotlib.figure import Figure
import numpy as np


#################
# Class OrderList
#################
class OrderList(wx.Panel):
    def __init__(self, parent):
        """Constructor"""
        wx.Panel.__init__(self, parent)
        self.InitUI()

    def InitUI(self):

        self.SetBackgroundColour('#EEEEEE')
        rows = [('0', 'BTCUSDT', '31256.25', '31262.00', '0.21', '2.22', '3.16', '01d 11:15:12'),
                ('16', 'ADAUSDT', '1.25', '1.00', '0.21', '2.22', '3.16', '01d 11:15:12'),
                ('9', 'FOEM', '31256.25', '31262,00', '0.21', '2.22', '3.16', '01d 11:15:12'),
                ('36', 'DOGEUSDT', '31256.25', '31262,00', '0.21', '2.22', '3.16', '01d 11:15:12'),
                ('175', 'SHIBUSDT', '31256.25', '31262,00', '0.21', '2.22', '3.16', '01d 11:15:12'),
                ('216', 'MERDEUSDT', '31256.25', '31262,00', '0.21', '2.22', '3.16', '01d 11:15:12'),
                ('888', 'SLIPUSDT', '31256.25', '31262,00', '0.21', '2.22', '3.16', '01d 11:15:12')]

        self.list_ctrl = wx.ListCtrl(self, style=wx.LC_REPORT)

        self.list_ctrl.InsertColumn(0, "Number")
        self.list_ctrl.InsertColumn(1, "Crypto")
        self.list_ctrl.InsertColumn(2, "Buying")
        self.list_ctrl.InsertColumn(3, "Price")
        self.list_ctrl.InsertColumn(4, "Hull")
        self.list_ctrl.InsertColumn(5, "Gain")
        self.list_ctrl.InsertColumn(6, "Gain peak")
        self.list_ctrl.InsertColumn(7, "Duration")

        index = 0
        for row in rows:
            self.list_ctrl.InsertStringItem(index, row[0])
            self.list_ctrl.SetStringItem(index, 1, row[1])
            self.list_ctrl.SetStringItem(index, 2, row[2])
            self.list_ctrl.SetStringItem(index, 3, row[3])
            self.list_ctrl.SetStringItem(index, 4, row[4])
            self.list_ctrl.SetStringItem(index, 5, row[5])
            self.list_ctrl.SetStringItem(index, 6, row[6])
            self.list_ctrl.SetStringItem(index, 7, row[7])

            if index % 2:
                self.list_ctrl.SetItemBackgroundColour(index, "#F8F8F8")
            else:
                self.list_ctrl.SetItemBackgroundColour(index, (249, 246, 176))
            index += 1

        # Vbox for listctrl
        vbox = wx.BoxSizer(wx.VERTICAL)
        vbox.Add(self.list_ctrl, 0, wx.ALL | wx.EXPAND, 3)
        self.SetSizer(vbox)

        # hbox for button
        hbox1 = wx.BoxSizer(wx.HORIZONTAL)
        b1 = wx.Button(self, label='OK', size=(70,30))
        hbox1.Add(b1, flag=wx.LEFT|wx.BOTTOM, border=5)
        vbox.Add((-1, 10))
        vbox.Add(hbox1, flag=wx.ALIGN_RIGHT|wx.RIGHT, border=10)
        self.SetSizer(vbox)

        # vbox for graph
        t = np.arange(0.0, 10, 1.0)
        s = [0, 1, 0, 1, 0, 2, 1, 2, 1, 0]
        t1 = np.arange(0.0, 10, 1.0)
        s1 = [3, 1, 2, 1, 0, 1, 1, 2, 3, 3]

        # hbox for graphs
        nbFigures = 3
        hbox2 = wx.BoxSizer(wx.HORIZONTAL)
        self.figs = [Figure(figsize=(2.5, 2)) for _ in range(nbFigures)]
        self.axes = [fig.add_subplot(111) for fig in self.figs]
        self.canvases = [FigureCanvas(self, -1, fig) for fig in self.figs]
        for canvas in self.canvases:
            hbox2.Add(canvas, 1, wx.ALL | wx.EXPAND , 5)

        vbox.Add(hbox2, flag=wx.ALIGN_LEFT | wx.RIGHT | wx.ALL | wx.EXPAND, border=10)
        self.SetSizer(vbox)
        # self.axes[0].plot(t,s)
        self.axes[0].bar(x=t, height=s, width=0.9, color='blue')
        self.figs[0].set_facecolor('#EEEEEE')
        self.axes[0].set_facecolor('#AEEAFF')

        self.axes[0].grid(alpha=0.5)
        self.axes[0].set_title('Graph1')

        self.axes[1].plot(t1,s1, color='red')
        self.axes[1].set_facecolor('#FFE0E0')
        self.figs[1].set_facecolor('#EEEEEE')
        self.axes[1].grid()
        self.axes[1].set_title('Graph2')

        self.axes[2].bar(x=t, height=s1, width=0.9, color='orange')
        self.axes[2].set_facecolor('#FFFFE0')
        self.figs[2].set_facecolor('#EEEEEE')
        self.axes[2].grid()
        self.axes[2].set_title('Graph3')


class TabPanel(wx.Panel):
    def __init__(self, parent):
        wx.Panel.__init__(self, parent=parent)

        btn = wx.Button(self, label="Press Me")
        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(btn, 0, wx.ALL, 10)
        self.SetSizer(sizer)


class MainWindows(wx.Frame):

    def __init__(self, *args, **kwargs):
        super(MainWindows, self).__init__(*args, **kwargs)

        self.InitUI()

    def InitUI(self):
        # Set Frame options
        self.SetSize((800, 600))
        self.SetTitle('Binance Scalping')
        self.Centre()

        # NoteBook
        panel = wx.Panel(self)
        notebook = wx.Notebook(panel)
        tabSettings = TabPanel(notebook)
        tabAccount = TabPanel(notebook)
        tabCryptoList = TabPanel(notebook)
        tabOrders = OrderList(notebook)
        tabIndicators = TabPanel(notebook)
        tabStatistics = TabPanel(notebook)
        notebook.AddPage(tabSettings, 'Settings')
        notebook.AddPage(tabAccount, 'Account')
        notebook.AddPage(tabCryptoList, 'Cryptos List')
        notebook.AddPage(tabOrders, 'Orders')
        notebook.AddPage(tabIndicators, 'Indicators')
        notebook.AddPage(tabStatistics, 'Statistics')
        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(notebook, 1, wx.ALL|wx.EXPAND, 5)
        panel.SetSizer(sizer)

        # Menus bar
        menubar = wx.MenuBar() # Menu bar
        # Menu items
        fileMenu = wx.Menu()
        viewMenu = wx.Menu()
        aboutMenu = wx.Menu()

        # viewMenu tick option
        self.shst = viewMenu.Append(wx.ID_ANY, 'Show statusbar', 'Show Statusbar', kind=wx.ITEM_CHECK)
        self.shtl = viewMenu.Append(wx.ID_ANY, 'Show toolbar', 'Show Toolbar', kind=wx.ITEM_CHECK)
        viewMenu.Check(self.shst.GetId(), True)
        viewMenu.Check(self.shtl.GetId(), True)
        self.Bind(wx.EVT_MENU, self.ToggleStatusBar, self.shst)
        self.Bind(wx.EVT_MENU, self.ToggleToolBar, self.shtl)

        # Create menu
        menubar.Append(fileMenu, '&File')
        menubar.Append(viewMenu, '&View')
        menubar.Append(aboutMenu, '&About')
        self.SetMenuBar(menubar)

        # Create Toolbar
        self.toolbar = self.CreateToolBar()
        self.toolbar.AddTool(1, '', wx.Bitmap('Z:/Crypto/Scripts Python/Go.png'))
        self.toolbar.Realize()

        # Create Status Bar
        self.statusbar = self.CreateStatusBar()
        self.statusbar.SetStatusText('Ready')

        self.Layout()
        self.Show()

    def ToggleStatusBar(self, e):

        if self.shst.IsChecked():
            self.statusbar.Show()
        else:
            self.statusbar.Hide()

    def ToggleToolBar(self, e):

        if self.shtl.IsChecked():
            self.toolbar.Show()
        else:
            self.toolbar.Hide()


def main():

    app = wx.App()
    ex = MainWindows(None)
    app.MainLoop()

if __name__ == '__main__':
    main()

【问题讨论】:

    标签: python user-interface parameter-passing wxpython


    【解决方案1】:

    你有很多问题。我没有资格谈论你的线程问题,但是:

    2 如何与我的 GUI 共享数据(参数传递)

    只需将您的数据添加到大型机类的调用中

    main_frame = MainFrame(config)
    ...
    class MainFrame(wx.Frame):
        """Create MainFrame class."""
        def __init__(self, config, *args, **kwargs):
            super().__init__(None, *args, **kwargs)
            self.Title = config.title
            ...
    

    3 如何定期(如每秒)刷新小部件

    wxPython 自带a timer class

    wx.Timer 类允许您以指定的时间间隔执行代码。 它的精度是平台相关的,但一般不会好于1ms,也不会差于1s。

    监听 EVT_TIMER

    【讨论】:

    • 非常感谢您的回答。我认为 args 和 kwars 在那里传递参数而不是指定它们是什么。但实际上您的示例显示了一种硬编码的方式......我现在要尝试一下,因为我以前没有成功,但我的方式并不完全相同。调查计时器事件。谢谢指点
    • @StéphaneREY 有多种方法可以更新 GUI,具体取决于您如何构建代码,但一个简单的起点可能是使用 pubsub。至少对于概念证明。其他选项是参数,wx.events,监听 tcp 端口,使用文件或管道等
    • 谢谢罗尔夫。我要去查一下pubsuv和事件
    猜你喜欢
    • 1970-01-01
    • 2010-12-27
    • 2020-08-03
    • 1970-01-01
    • 2013-01-26
    • 2018-10-27
    • 1970-01-01
    • 1970-01-01
    • 2011-03-04
    相关资源
    最近更新 更多