如何解决wxPython - 无法在 __init__ 中调用类方法
我知道这可能是一个基本问题,但我刚刚进入 GUI 构建领域,不需要在课堂上涉足太多。我有一些代码(见下文)来处理程序的 GUI 部分(CLI 版本已经完美运行,但是每当他们看到 CLI 时管理就会跑山……),但我无法完全理解锻炼。仅供参考,在 Windows 10 上运行 python 3.9.1 和 wxPython 4.1.1 Phoenix(尽管 wx.version
也会吐出 wxWidgets 3.1.5
,如果相关的话)
很多代码都是基于示例/其他人在这里问的东西,不幸的是我找不到原始帖子来感谢他们,但这真的只是为了学习,一旦我掌握了我的东西'我正在做我将从头开始写所有东西。所以对于原作者,我深表歉意,但我非常感谢你!
该程序将显示一个“开始”屏幕(框架),只有一个标题和一个按钮。单击该按钮时,将打开一个模式文件对话框,用户可以在其中选择要使用的 .csv 数据文件,起始帧消失,并在右侧窗格中(在网格调整器中)出现一个带有数据视图的新帧和左窗格中的一些下拉菜单和单选按钮。最后一个下拉列表 (self.inputNum
) 将绑定到一个事件处理程序,该事件处理程序将添加许多额外的下拉列表供用户选择要分析的不同目标(课程数量由他们在self.inputNum
组合框)。但是,在运行脚本时,出现错误
Traceback (most recent call last):
File "C:\Python\Scripts\wxLOD_2class_panelbased.py",line 98,in _OnStart
self.frm2 = Frame2(None)
File "C:\Python\Scripts\wxLOD_2class_panelbased.py",line 154,in __init__
self.CreateGrid(datalist,cols)
AttributeError: 'Frame2' object has no attribute 'CreateGrid'
我在这里搜索,发现有人有类似的问题(在同一类的 init 中调用类方法),但“正确”的答案是使用 {{ 1}}(OP 一直称它为 self.classmethodname(args)
,我已经在这样做了。
为草率的格式提前道歉。我试图尽可能地清理它,但由于我不知道错误来自哪里,我不想偏离我用来构建我目前拥有的混乱的(工作)示例太远。请参阅下面的我的脚本、我基于“Frame2”的稍微修改的脚本以及屏幕截图。
我的代码(我知道在一行中导入模块是不受欢迎的,但我为这篇文章压缩了很多):
classmethodname(args)
我基于我的“Frame2”的稍微编辑但有效的代码如下(不知道他为什么把它分成 3 个类,或者 import os,sys,csv,time,math,warnings,collections,wx,wx.grid,scipy
import numpy as np
import matplotlib.pyplot as plt
import win32gui as wg
import pandas as pd
from datetime import datetime
from scipy.stats import norm
from tkinter import filedialog
from tkinter import *
from decimal import *
pd.options.mode.chained_assignment = None # default='warn'
class StartFrame(wx.Frame):
"""App controller class"""
FRAME_MIN_SIZE = (900,600)
def __init__(self,parent):
wx.Frame.__init__(self,parent=parent,id=wx.ID_ANY,title="LOD Calculator",size=wx.Size(900,600),style=wx.CAPTION|wx.CLOSE_Box|wx.MINIMIZE_Box|wx.SYstem_MENU|wx.TAB_TRAVERSAL)
self.SetSizeHints(wx.DefaultSize,wx.DefaultSize)
self.startpnl = wx.Panel(self)
self.startvsizer = wx.BoxSizer(wx.VERTICAL)
self.startbtnsizer = wx.BoxSizer(wx.HORIZONTAL)
# make title and subtitle,format fonts
self.st = wx.StaticText(self.startpnl,style=wx.ALIGN_CENTER,label="DCB LoD Calculator")
self.font = self.st.GetFont()
self.font.PointSize += 10
self.font = self.font.Bold()
self.st.SetFont(self.font)
self.stsub = wx.StaticText(self.startpnl,label="Probit/Linear Regression Method")
self.fontsub = self.stsub.GetFont()
self.fontsub.PointSize += 2
self.stsub.SetFont(self.fontsub)
# make the "begin" button to start the script
self.btn = wx.Button(self.startpnl,wx.ID_ANY,"Start Analysis",\
size = (200,60))
self.btn.Bind(wx.EVT_BUTTON,self._OnStart)
self.startbtnsizer.AddStretchSpacer()
self.startbtnsizer.Add(self.btn,wx.CENTER)
self.startbtnsizer.AddStretchSpacer()
self.startvsizer.Add(self.st,wx.SizerFlags().Expand().Border(wx.ALL,25))
self.startvsizer.Add(self.stsub,25))
self.startvsizer.AddStretchSpacer()
self.startvsizer.Add(self.startbtnsizer,25))
self.startvsizer.AddStretchSpacer()
self.startpnl.SetSizerAndFit(self.startvsizer)
# create a menu & status bar
self.makeMenuBar()
self.CreateStatusBar()
self.SetStatusText("PLACEHOLDER -- STATUS BAR")
self.Center(wx.BOTH)
def makeMenuBar(self):
fileMenu = wx.Menu()
helloItem = fileMenu.Append(-1,"&Hello...\tCtrl-H","Help string shown in status bar for this menu item")
fileMenu.AppendSeparator()
exitItem = fileMenu.Append(wx.ID_EXIT)
helpMenu = wx.Menu()
aboutItem = helpMenu.Append(wx.ID_ABOUT)
menuBar = wx.MenuBar()
menuBar.Append(fileMenu,"&File")
menuBar.Append(helpMenu,"&Help")
self.SetMenuBar(menuBar)
self.Bind(wx.EVT_MENU,self.OnHello,helloItem)
self.Bind(wx.EVT_MENU,self.OnExit,exitItem)
self.Bind(wx.EVT_MENU,self.OnAbout,aboutItem)
def OnExit(self,event):
"""Close frame & terminate app"""
self.Close(True)
def OnHello(self,event):
"""oh hey what's up"""
wx.MessageBox("Stuff would go here",\
"The dialog with the stuff would have this title")
def OnAbout(self,event):
"""for displaying 'about' dialog"""
wx.MessageBox("Main dialog Box text for About",\
"About title text",wx.OK|wx.ICON_informatION)
def _OnStart(self,event):
self.Hide()
self.frm2 = Frame2(None)
self.frm2.Show()
class Frame2(wx.Frame):
"""Data load frame"""
FRAME_MIN_SIZE = (900,style=wx.CAPTION|wx.CLOSE_Box|wx.MINIMIZE_Box|wx.SYstem_MENU|wx.TAB_TRAVERSAL)
self.SetSizeHints(wx.DefaultSize,wx.DefaultSize)
self.dirname = os.getcwd()
filedlg = wx.FileDialog(self,'Choose a file',os.getcwd(),\
'','CSV files (*.csv)|*.csv|All files(*.*)|*.*',wx.FD_OPEN)
if filedlg.ShowModal() == wx.ID_OK:
self.dirname = filedlg.GetDirectory()
self.filename = filedlg.GetFilename()
self.path = os.path.join(self.dirname,self.filename)
self.file = open(self.path,'r')
dialect = csv.Sniffer().sniff(self.file.read(1024),\
delimiters = ";|,")
self.file.seek(0)
csvfile = csv.reader(self.file,dialect)
filedata = []
filedata.extend(csvfile)
self.file.seek(0)
datasample = self.file.read(2048)
self.file.seek(0)
if csv.Sniffer().has_header(datasample):
self.cols = next(csvfile)
self.datalist = []
self.datalist.extend(filedata[1:len(filedata)])
else:
self.cols = []
for idx in range(len(next(csvfile))):
self.cols.append(f'col_{i}')
self.file.seek(0)
self.datalist = filedata
self.file.close()
# Create Sizers
Sizer1 = wx.BoxSizer(wx.HORIZONTAL)
paraLsizer = wx.BoxSizer(wx.VERTICAL)
paraRsizer = wx.BoxSizer(wx.VERTICAL)
# Create Panels
self.paraLpnl = wx.Panel(self,wx.DefaultPosition,\
wx.DefaultSize,wx.TAB_TRAVERSAL)
self.pararpnl = wx.Panel(self,wx.TAB_TRAVERSAL)
### FOLLOWING LINE SPITS THE ERROR
### HAVE TRIED USING BOTH self.datalist/self/cols AND JUST datalist/cols - NO EFFECT
self.CreateGrid(self.datalist,self.cols)
# Create Widgets
self.reImportButton = wx.Button(self.paraLpnl,\
wx.ID_ANY,u"Import New CSV File",0)
self.paraInput = wx.StaticText(self.paraLpnl,\
label="Select input column:",style = wx.ALIGN_CENTER_HORIZONTAL)
self.inputcb = wx.ComboBox(self.paraLpnl,value=cols[0],\
choices=cols,style = wx.CB_READONLY)
self.logbtn = wx.RadioButton(self.paraLpnl,label='Check button\
if input is in log10(conc.)')
self.logbtn.SetValue(False)
numInputs = ['1','2','3','4','5','6','7','8','9']
self.inputNumLabel = wx.StaticText(self.paraLpnl,\
label="Select number of targets",style = wx.ALIGN_CENTER_HORIZONTAL)
self.inputNum = wx.ComboBox(self.paraLpnl,value='',\
choices = numInputs,style = wx.CB_READONLY)
# Add stuff to sub-sizers,set them,and fit stuff
paraLsizer.Add(self.reImportButton,wx.ALL,5)
paraLsizer.Add(self.paraInput,5)
paraLsizer.Add(self.inputcb,5)
paraLsizer.Add(self.logbtn,5)
paraLsizer.Add(self.inputNumLabel,5)
paraLsizer.Add(self.inputNum,5)
self.paraLpnl.SetSizer(paraLsizer)
self.paraLpnl.Layout()
paraLsizer.Fit(self.paraLpnl)
paraRsizer.Add(self.grid,1,wx.EXPAND)
self.pararpnl.SetSizer(paraRsizer)
self.pararpnl.Layout()
paraRsizer.Fit(self.pararpnl)
# Add panels (containing sub-sizers) to main sizer
Sizer1.Add(self.paraLpnl,wx.EXPAND |wx.BottOM,5)
Sizer1.Add(self.pararpnl,wx.EXPAND |wx.ALL,5)
# Set main sizer for the window; add status and menu bars
self.SetSizer(Sizer1)
StartFrame.makeMenuBar(self)
StartFrame.CreateStatusBar(self)
StartFrame.SetStatusText(self,"PLACEHOLDER -- STATUS BAR")
# Finally,lay the whole window out and center it.
self.Layout()
self.Centre(wx.BOTH)
#create the grid
def createGrid(self,datalist,colnames):
if getattr(self,'grid',0): self.grid.Destroy()
self.grid = wx.grid.Grid(self.pararpnl,0)
self.grid.CreateGrid(len(datalist),len(colnames)) #create grid,same size as file (rows,cols)
#fill in headings
for i in range(len(colnames)):
self.grid.SetColLabelValue(i,colnames[i])
#populate the grid
for row in range(len(datalist)):
for col in range(len(colnames)):
try:
self.grid.SetCellValue(row,col,datalist[row][col])
except:
pass
self.grid.AutoSizeColumns(False) # size columns to data (from cvsomatic.py)
self.twiddle()
def twiddle(self):
x,y = self.GetSize()
self.SetSize((x,y+1))
self.SetSize((x,y))
def Exit(self,event):
if getattr(self,'file',0):
self.file.close()
self.Close(True)
import wx.lib.mixins.inspection
app = wx.App()
frm = StartFrame(None)
frm.Show()
wx.lib.inspection.inspectionTool().Show()
app.MainLoop()
类的用途是什么):
csv_view(wx.App)
我的应用程序启动时的屏幕(在您尝试在“开始分析”按钮产生的模式对话框中选择 .csv 文件之前一直有效)、我用来引导第二帧打开的应用程序,以及相同的导入 csv 后的应用程序。
此外,任何不直接涉及我的问题的改进/建议/更正都非常受欢迎。我是开发这方面的新手,需要我能得到的所有帮助!
解决方法
抱歉各位,当函数被定义为 CreateGrid()
时,我的咖啡前大脑正在调用 createGrid()
。代码中还有一些其他错误(引用我不再实现的按钮的事件处理程序、从不同的类调用 StartFrame.makeMenuBar
而不导入调用的函数 StartFrame.makeMenuBar
等)。>
但仍然可以随意指出我正在做的低效率和冗余以及其他各种非 Pythonic 的事情。还在学习:)
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。