将多个 wxpython NumCtrl 控件中的数据存储到数据结构中以供 matplotlib 绘图

44 阅读2分钟

在一个 wxpython 项目中,我需要将多个 NumCtrl 控件中的数据存储到一个数据结构中,以便使用 matplotlib 进行绘图。这些数据是不同角度下的计数,分为有准直器 (C) 和无准直器 (U) 两种情况。当用户点击“绘制”按钮时,程序应该从每个 NumCtrl 控件中获取数据,然后将数据存储到数据结构中,最后使用 matplotlib 绘制出带有这两个系列数据的图形。

以下是我尝试过的代码:

# 导入必要的库
import wx
import matplotlib.pyplot as plt

# 创建一个 wxpython 应用程序
class MyFrame(wx.Frame):
    def __init__(self):
        super().__init__(None, title='wxpython NumCtrl to Matplotlib')

        # 创建一个面板
        panel = wx.Panel(self)

        # 创建一个网格布局器
        sizer = wx.GridSizer(cols=2, hgap=5, vgap=5)

        # 创建 NumCtrl 控件
        numctrl_ccm90 = NumCtrl(panel, -1, style=wx.TE_PROCESS_ENTER | wx.TE_PROCESS_TAB)
        numctrl_ucm90 = NumCtrl(panel, -1, style=wx.TE_PROCESS_ENTER | wx.TE_PROCESS_TAB)
        numctrl_ccp90 = NumCtrl(panel, -1, style=wx.TE_PROCESS_ENTER | wx.TE_PROCESS_TAB)
        numctrl_ucp90 = NumCtrl(panel, -1, style=wx.TE_PROCESS_ENTER | wx.TE_PROCESS_TAB)
        ...
        # 其他角度的 NumCtrl 控件

        # 创建标签
        labels = [
            'Angle (°)',
            'Counts (C)',
            'Counts (U)',
        ]

        # 将控件和标签添加到布局器中
        for label, ctrl in zip(labels, [numctrl_ccm90, numctrl_ucm90, numctrl_ccp90, numctrl_ucp90, ...]):
            sizer.Add(wx.StaticText(panel, -1, label), 0, wx.ALIGN_CENTER)
            sizer.Add(ctrl, 1, wx.EXPAND)

        # 创建“绘制”按钮
        btn_plot = wx.Button(panel, -1, 'Plot')
        btn_plot.Bind(wx.EVT_BUTTON, self.OnPlot)

        # 将“绘制”按钮添加到布局器中
        sizer.Add(btn_plot, 0, wx.ALIGN_CENTER, 5)

        # 将布局器添加到面板中
        panel.SetSizer(sizer)

        # 将面板添加到窗口中
        self.SetClientSize(sizer.Fit(panel))

    def OnPlot(self, event):
        # 获取 NumCtrl 控件中的数据
        data = []
        for ctrl in [numctrl_ccm90, numctrl_ucm90, numctrl_ccp90, numctrl_ucp90, ...]:
            data.append(ctrl.GetValue())

        # 将数据转换为字典
        data_dict = {
            'Angle': [angle for angle in range(-90, 100, 15)],
            'Counts (C)': data[::2],
            'Counts (U)': data[1::2],
        }

        # 使用 matplotlib 绘制图形
        plt.scatter(data_dict['Angle'], data_dict['Counts (C)'])
        plt.scatter(data_dict['Angle'], data_dict['Counts (U)'])
        plt.xlabel('Angle')
        plt.ylabel('Counts')
        plt.title('Counts vs. Angle')
        plt.show()

# 创建一个应用程序对象
app = wx.App()

# 创建一个窗口对象
frame = MyFrame()

# 启动应用程序
app.MainLoop()

2. 解决方案

在上面的代码中,我已经将数据存储在一个字典中,然后使用 matplotlib 绘制了图形。但是,这种方法存在一个问题:如果用户输入了非数字字符,程序就会崩溃。

为了解决这个问题,我们可以使用 try...except 语句来捕获异常。当用户输入非数字字符时,程序将不会崩溃,而是会显示一个错误消息。

以下是修改后的代码:

def OnPlot(self, event):
    # 获取 NumCtrl 控件中的数据
    data = []
    for ctrl in [numctrl_ccm90, numctrl_ucm90, numctrl_ccp90, numctrl_ucp90, ...]:
        try:
            data.append(int(ctrl.GetValue()))
        except ValueError:
            wx.MessageBox('Invalid input. Please enter a number.', 'Error', wx.OK | wx.ICON_ERROR)
            return

    # 将数据转换为字典
    data_dict = {
        'Angle': [angle for angle in range(-90, 100, 15)],
        'Counts (C)': data[::2],
        'Counts (U)': data[1::2],
    }

    # 使用 matplotlib 绘制图形
    plt.scatter(data_dict['Angle'], data_dict['Counts (C)'])
    plt.scatter(data_dict['Angle'], data_dict['Counts (U)'])
    plt.xlabel('Angle')
    plt.ylabel('Counts')
    plt.title('Counts vs. Angle')
    plt.show()

现在,当用户输入非数字字符时,程序不会崩溃,而是会显示一条错误消息。