Python - 帮助自定义 wx.Python (pyDev) 类
我在这个程序上遇到了瓶颈。我想创建一个类,能够在按钮使用时控制它的BIP(可能是指某种状态或效果)。到目前为止,我写的代码是这样的(见下文)。但是它一直报一个奇怪的错误 TypeError: 'module' object is not callable
。我之前用C++和C#写过代码(感觉用 #include...
这种方式简单多了),但我对这个错误完全不懂,谷歌也没能帮到我……我知道我需要一些真正的帮助,特别是在语法方面,任何建议都很有用。我知道这个问题有很多人问过,我非常感激任何帮助!
注意:基础代码可以在 这里 找到,用来创建这个“自定义按钮类”的框架。
自定义按钮
import wx
from wxPython.wx import *
class Custom_Button(wx.PyControl):
# The BMP's
# AM I DOING THIS RIGHT? - I am trying to get empty 'global'
# variables within the class
Mouse_over_bmp = None #wxEmptyBitmap(1,1,1) # When the mouse is over
Norm_bmp = None #wxEmptyBitmap(1,1,1) # The normal BMP
Push_bmp = None #wxEmptyBitmap(1,1,1) # The down BMP
Pos_bmp = wx.Point(0,0) # The posisition of the button
def __init__(self, parent, NORM_BMP, PUSH_BMP, MOUSE_OVER_BMP,
pos, size, text="", id=-1, **kwargs):
wx.PyControl.__init__(self,parent, id, **kwargs)
# The conversions, hereafter, were to solve another but. I don't know if it is
# necessary to do this since the source being given to the class (in this case)
# is a BMP - is there a better way to prevent an error that i have not
# stumbled accost?
# Set the BMP's to the ones given in the constructor
self.Mouse_over_bmp = wx.Bitmap(wx.Image(MOUSE_OVER_BMP, wx.BITMAP_TYPE_ANY).ConvertToBitmap())
self.Norm_bmp = wx.Bitmap(wx.Image(NORM_BMP, wx.BITMAP_TYPE_ANY).ConvertToBitmap())
self.Push_bmp = wx.Bitmap(wx.Image(PUSH_BMP, wx.BITMAP_TYPE_ANY).ConvertToBitmap())
self.Pos_bmp = self.pos
self.Bind(wx.EVT_LEFT_DOWN, self._onMouseDown)
self.Bind(wx.EVT_LEFT_UP, self._onMouseUp)
self.Bind(wx.EVT_LEAVE_WINDOW, self._onMouseLeave)
self.Bind(wx.EVT_ENTER_WINDOW, self._onMouseEnter)
self.Bind(wx.EVT_ERASE_BACKGROUND,self._onEraseBackground)
self.Bind(wx.EVT_PAINT,self._onPaint)
self._mouseIn = self._mouseDown = False
def _onMouseEnter(self, event):
self._mouseIn = True
def _onMouseLeave(self, event):
self._mouseIn = False
def _onMouseDown(self, event):
self._mouseDown = True
def _onMouseUp(self, event):
self._mouseDown = False
self.sendButtonEvent()
def sendButtonEvent(self):
event = wx.CommandEvent(wx.wxEVT_COMMAND_BUTTON_CLICKED, self.GetId())
event.SetInt(0)
event.SetEventObject(self)
self.GetEventHandler().ProcessEvent(event)
def _onEraseBackground(self,event):
# reduce flicker
pass
def _onPaint(self, event):
dc = wx.BufferedPaintDC(self)
dc.SetFont(self.GetFont())
dc.SetBackground(wx.Brush(self.GetBackgroundColour()))
dc.Clear()
dc.DrawBitmap(self.Norm_bmp)
# draw whatever you want to draw
# draw glossy bitmaps e.g. dc.DrawBitmap
if self._mouseIn: # If the Mouse is over the button
dc.DrawBitmap(self, self.Mouse_over_bmp, self.Pos_bmp, useMask=False)
if self._mouseDown: # If the Mouse clicks the button
dc.DrawBitmap(self, self.Push_bmp, self.Pos_bmp, useMask=False)
Main.py
import wx
import Custom_Button
from wxPython.wx import *
ID_ABOUT = 101
ID_EXIT = 102
class MyFrame(wx.Frame):
def __init__(self, parent, ID, title):
wxFrame.__init__(self, parent, ID, title,
wxDefaultPosition, wxSize(400, 400))
self.CreateStatusBar()
self.SetStatusText("Program testing custom button overlays")
menu = wxMenu()
menu.Append(ID_ABOUT, "&About", "More information about this program")
menu.AppendSeparator()
menu.Append(ID_EXIT, "E&xit", "Terminate the program")
menuBar = wxMenuBar()
menuBar.Append(menu, "&File");
self.SetMenuBar(menuBar)
self.Button1 = Custom_Button(self, parent, -1,
"D:/Documents/Python/Normal.bmp",
"D:/Documents/Python/Clicked.bmp",
"D:/Documents/Python/Over.bmp",
wx.Point(200,200), wx.Size(300,100))
EVT_MENU(self, ID_ABOUT, self.OnAbout)
EVT_MENU(self, ID_EXIT, self.TimeToQuit)
def OnAbout(self, event):
dlg = wxMessageDialog(self, "Testing the functions of custom "
"buttons using pyDev and wxPython",
"About", wxOK | wxICON_INFORMATION)
dlg.ShowModal()
dlg.Destroy()
def TimeToQuit(self, event):
self.Close(true)
class MyApp(wx.App):
def OnInit(self):
frame = MyFrame(NULL, -1, "wxPython | Buttons")
frame.Show(true)
self.SetTopWindow(frame)
return true
app = MyApp(0)
app.MainLoop()
错误信息(和追踪信息)
/home/wallter/python/Custom Button overlay/src/Custom_Button.py:8: DeprecationWarning: The wxPython compatibility package is no longer automatically generated or actively maintained. Please switch to the wx package as soon as possible.
我在使用wxPython时一直无法解决这个问题,有什么帮助吗?
from wxPython.wx import *
Traceback (most recent call last):
File "/home/wallter/python/Custom Button overlay/src/Main.py", line 57, in <module>
app = MyApp(0)
File "/usr/lib/python2.6/dist-packages/wx-2.8-gtk2-unicode/wx/_core.py", line 7978, in __init__
self._BootstrapApp()
File "/usr/lib/python2.6/dist-packages/wx-2.8-gtk2-unicode/wx/_core.py", line 7552, in _BootstrapApp
return _core_.PyApp__BootstrapApp(*args, **kwargs)
File "/home/wallter/python/Custom Button overlay/src/Main.py", line 52, in OnInit
frame = MyFrame(NULL, -1, "wxPython | Buttons")
File "/home/wallter/python/Custom Button overlay/src/Main.py", line 32, in __init__
wx.Point(200,200), wx.Size(300,100))
TypeError: 'module' object is not callable
我尝试过去掉 "wx.Point(200,200), wx.Size(300,100))
",结果错误信息就转到上面那行了。我这样声明对吗?求助!
之前关于这段代码的问题可以在 这里 找到。
2 个回答
在Python中导入一个模块,可以想象成在C#中导入一个更高一级的命名空间。
举个例子,在C#中,当你写
import System.IO;
时,你可以直接使用
var file = new File("a.txt");
但是如果你只写了import System;
,你就得写
var file = new IO.File("a.txt");
在Python中,如果你做了类似的操作import System.IO
,你仍然需要写
file = IO.File("a.txt")
如果你想在Python中不需要加前缀,你可以写
from System.IO import File
或者from System.IO import *
,这就更像C#的写法了。
能够指定特定类的好处在于,当你有很多类的命名空间,或者你想导入的两个模块中有相同的类名时。在C#中,你要么需要给命名空间起个别名,要么写出完整的名字,而在Python中,你可以直接导入你想要的特定类。
把整个代码注释掉后,错误就消失了,还弹出了一个窗口:
self.Button1 = Custom_Button(self, parent, -1,
"D:/Documents/Python/Normal.bmp",
"D:/Documents/Python/Clicked.bmp",
"D:/Documents/Python/Over.bmp",
wx.Point(200,200), wx.Size(300,100))
所以这算是有进展了……
好吧,找到了问题:
问题出在导入的 Custom_Button。这个只是导入了模块。你应该使用那个模块里同名的类,所以:
from Custom_Button import Custom_Button
这样问题就解决了。接下来你可以继续处理下一个错误……
一开始我有点难以发现问题,因为你用的编程风格和 Python 不太一样。与其他编程语言不同,Python 有一个特定的编程风格,这在一个文档里有说明。虽然有些地方会有小的偏差,但大多数优秀的 Python 开发者还是会比较遵循这个风格,因为这样更有道理,也能更容易发现问题。
谷歌的版本在此基础上增加了更多内容,甚至有点更严格。
所以在这个例子中,模块文件应该命名为 custom_button.py 和 main.py。类的名字应该是 CustomButton。