Wxpython producing error - python

I am trying to run a progrom from the book "Remote Sensing Raster Programming" for calculating NDVI from raster dataset. Program reads two separate raster bands NIR and RED using GDAL and executes following equation NDVI = (NIR-RED)/(NIR+RED).
But it is producing error and GUI is not openning. I am trying to learn wxPython and I will appreciate any help to sort out this problem.
Error -
Traceback (most recent call last):
File "C:\Users\User\Desktop\ndvi.py", line 189, in <module>
frame = MyFrame(None)
File "C:\Users\User\Desktop\ndvi.py", line 48, in __init__
self.make_fb()
File "C:\Users\User\Desktop\ndvi.py", line 112, in make_fb
fileMode=wx.OPEN,
AttributeError: 'module' object has no attribute 'OPEN'
Code for the program
#!/usr/bin/python
# -*- coding: cp1252 -*-
import wx
import wx.lib.filebrowsebutton as filebrowse
import os
# For Image Processing
import numpy
from osgeo import gdalnumeric
from osgeo import gdal
from osgeo import gdal_array
from osgeo.gdalconst import *
# Define satellite bands
redchan = ''
nirchan = ''
# Define output file name
output = ''
# Define Info Message
overview = """Vegetation Index Processing.
Calculates vegetation indices based on biophysical parameters.
NDVI: Normalized Difference Vegetation Index
NDVI = (band 2 - band 1) / (band 2 + band 1)
NDVI = (NIR - Red) / (NIR + Red)
Rouse J., Haas R., Schell J. and Deering D. (1974).
Monitoring vegetation systems in the Great Plains
with ERTS. In Proceedings of the Third Earth
Resources Technology Satellite-1 Symposium, Greenbelt."""
class MyFrame(wx.Frame):
def __init__(self,parent, id=-1, title='Normalized Difference Vegetation Index Processing',
pos=(0,0),
size=(400,400),
style=wx.DEFAULT_FRAME_STYLE):
wx.Frame.__init__(self, parent, id, title, pos, size, style)
self.lognull = wx.LogNull()
# Input Filenames
self.redchan = redchan
self.nirchan = nirchan
self.output = output
# Construct Interface
self.make_text()
self.make_buttons()
self.make_fb()
self.mbox = wx.BoxSizer(wx.VERTICAL)
self.mbox.Add((10,10))
self.mbox.Add(self.text, 1, wx.EXPAND|wx.CENTER, 10)
self.mbox.Add((10,10))
self.mbox.Add((10,10))
self.mbox.Add(self.cc2, 1, wx.EXPAND, 10)
self.mbox.Add(self.cc3, 1, wx.EXPAND, 10)
self.mbox.Add(self.cc6, 1, wx.EXPAND, 10)
self.mbox.Add((10,10))
self.mbox.Add((10,10))
self.mbox.Add(self.bbox, 1, wx.CENTER, 10)
self.mbox.Add((10,10))
self.SetSizer(self.mbox)
self.bindEvents()
# Process Equations, Handling and saving of output
def OnOK(self,event):
print "red: ", self.redchan, " nir:",self.nirchan, " out:", self.output
if(self.redchan==''):
self.OnFileInError()
elif(self.nirchan==''):
self.OnFileInError()
else:
self.redband = gdal_array.LoadFile(self.redchan)
self.nirband = gdal_array.LoadFile(self.nirchan)
# NDVI
self.result=self.ndvi(self.redband, self.nirband)
# prepare/create output file
tmp = gdal.Open(str(self.redchan))
geoT = tmp.GetGeoTransform()
proJ = tmp.GetProjection()
tmp = None
out = gdal_array.OpenArray(self.result )
out.SetGeoTransform( geoT )
out.SetProjection( proJ )
driver = gdal.GetDriverByName( 'GTiff' )
driver.CreateCopy( self.output, out )
self.Destroy()
def ndvi( self, redchan, nirchan ):
"""
Normalized Difference Vegetation Index
ndvi( redchan, nirchan )
"""
result = 1.0*( nirchan - redchan )
result /= 1.0*( nirchan + redchan )
return result
def OnFileInError(self):
dlg = wx.MessageDialog(self,
'Minimum files to add:\n\n Input files => Red and NIR \n One Output file',
'Error',wx.OK | wx.ICON_INFORMATION)
dlg.ShowModal()
dlg.Destroy()
# Path+filename seek and set
def make_fb(self):
# get current working directory
self.dirnm = os.getcwd()
self.cc2 = filebrowse.FileBrowseButton(
self, -1, size=(50, -1), labelText='RED:',
startDirectory = self.dirnm,
fileMode=wx.OPEN,
changeCallback = self.fbbCallback2,
)
self.cc3 = filebrowse.FileBrowseButton(
self, -1, size=(50, -1), labelText='NIR:',
startDirectory = self.dirnm,
fileMode=wx.OPEN,
changeCallback = self.fbbCallback3
)
self.cc6 = filebrowse.FileBrowseButton(
self, -1, size=(50, -1), labelText='OUT File:',
startDirectory = self.dirnm,
fileMask='*.tif',
fileMode=wx.SAVE,
changeCallback = self.fbbCallback6
)
# Collect path+filenames
def fbbCallback2(self, evt):
self.redchan = str(evt.GetString())
def fbbCallback3(self, evt):
self.nirchan = str(evt.GetString())
def fbbCallback6(self, evt):
self.output = str(evt.GetString())
# Front text
def make_text(self):
self.text = wx.StaticText(self, -1, '''\n\tThis is a full Python +
WxPython application,\n\tprocessing NDVI through the use
of \n\tGDAL Python bindings and numpy''')
# Bottom buttons
def make_buttons(self):
self.bbox = wx.BoxSizer(wx.HORIZONTAL)
# OnOK
bmp0 = wx.ArtProvider.GetBitmap(wx.ART_TICK_MARK, wx.ART_TOOLBAR, (32,32))
self.b0 = wx.BitmapButton(self, 20, bmp0, (20, 20),
(bmp0.GetWidth()+50, bmp0.GetHeight()+10), style=wx.NO_BORDER)
self.b0.SetToolTip("Process")
self.bbox.Add(self.b0,1,wx.CENTER,10)
# OnCancel
bmp1 = wx.ArtProvider.GetBitmap(wx.ART_CROSS_MARK, wx.ART_TOOLBAR, (32,32))
self.b1 = wx.BitmapButton(self, 30, bmp1, (20, 20),
(bmp1.GetWidth()+50, bmp1.GetHeight()+10), style=wx.NO_BORDER)
self.b1.SetToolTip("Abort")
self.bbox.Add(self.b1,1,wx.CENTER,10)
# OnInfo
bmp2 = wx.ArtProvider.GetBitmap(wx.ART_HELP, wx.ART_TOOLBAR, (32,32))
self.b2 = wx.BitmapButton(self, 40, bmp2, (20, 20),
(bmp2.GetWidth()+50, bmp2.GetHeight()+10), style=wx.NO_BORDER)
self.b2.SetToolTip("Help/Info.")
self.bbox.Add(self.b2,1,wx.CENTER,10)
def bindEvents(self):
self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
self.Bind(wx.EVT_BUTTON, self.OnOK, self.b0)
self.Bind(wx.EVT_BUTTON, self.OnCancel, self.b1)
self.Bind(wx.EVT_BUTTON, self.OnInfo, self.b2)
def OnCloseWindow(self, event):
self.Destroy()
def OnCancel(self, event):
self.Destroy()
def OnInfo(self,event):
dlg = wx.MessageDialog(self, overview,'Help', wx.OK | wx.ICON_INFORMATION)
dlg.ShowModal()
dlg.Destroy()
class MainApp(wx.App):
def OnInit(self):
frame = MainFrame(None)
frame.Show(True)
self.SetTopWindow(frame)
return True
if __name__ == '__main__':
app = wx.App()
frame = MyFrame(None)
frame.Show()
app.MainLoop()

If you are using wxPython 4 (Phoenix), then you want to use wx.FD_OPEN instead of wx.OPEN. I'm not sure why that's not in the Migration Guide or the Classic Vs. Phoenix page though

Related

Can't insert graph in a wxPython GUI

I am trying to make a telemetry software for a college project, that's why I'm using wxPython to make a GUI. I'm currently trying to make a function that displays a graph of brake_p and throttle in function of the time after I opened the entry file.
The code looks good to me, however it looks like there is an error inside the module that blocks me from succeeding.
Here is the error I get when I open the entry file :
> PS C:\Users\Adrie\OneDrive\Bureau\telemetry python> &
> 'C:\Users\Adrie\AppData\Local\Microsoft\WindowsApps\python3.10.exe'
> 'c:\Users\Adrie\.vscode\extensions\ms-python.python-2022.20.1\pythonFiles\lib\python\debugpy\adapter/../..\debugpy\launcher' '54993' '--' 'c:\Users\Adrie\OneDrive\Bureau\telemetry
> python\v0601.py' Traceback (most recent call last): File
> "c:\Users\Adrie\OneDrive\Bureau\telemetry python\v0601.py", line 105,
> in OnOpen self.OpenData(file) File
> "c:\Users\Adrie\OneDrive\Bureau\telemetry python\v0601.py", line 144,
> in OpenData self.canvas.Draw(self.drawBrakeThrottlePlot) File
> "C:\Users\Adrie\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\LocalCache\local-packages\Python310\site-packages\wx\lib\plot\plotcanvas.py",
> line 1750, in Drawgraphics.logScale = self.logScale AttributeError:
> 'method' object has no attribute 'logScale' PS
> C:\Users\Adrie\OneDrive\Bureau\telemetry python>
The error I can't understand is the part in bold caracters,as it is nowhere in my code :
Drawgraphics.logScale = self.logScale
AttributeError: 'method' object has no attribute 'logScale'
I 'd like to add I plan to add a bar marker on the graph that would be either automatically move at real-time, or either movable by the user so the time at the marker would be used to display in other widget data corresponding to the exact instant (like in the matlab simulink graph/scopes), which means I can't store the graph as a bitmap but really as a graph/plot.
I tried to switch to another library to import the plot into the wxFrame but I just can't make it work as they look more complicated to me, so I got back to this method.
Here is the code :
import wx
import numpy as np
import matplotlib.pyplot as plt
from wx.lib.plot import PlotCanvas, PlotGraphics, PolyLine, PolyMarker
import wxmplot.interactive as wi
# Variables initialization
time, speed, distance, brake_p, throttle, g_x, g_y, g_z, gps_x, gps_y, omega_fl, omega_fr = ([] for i in range(12))
r=1 # Wheel radius, will implement a feature to make it editable by the user later
class MainWindow(wx.Frame):
def __init__(self, *args, **kw):
super(MainWindow, self).__init__(*args, **kw)
# Create a panel and add it to the main window
panel = wx.Panel(self)
# Set the panel as the main window's sizer
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(panel, 1, wx.EXPAND)
self.SetSizer(sizer)
# Set the window's min size
self.SetMinSize((1280,720))
# create a menu bar
self.makeMenuBar()
# and a status bar
self.CreateStatusBar()
self.SetStatusText("v 0.1")
# put some text with a larger bold font on it
st = wx.StaticText(panel, label="Welcome on the EFT's Telemetry software !")
font = st.GetFont()
font.PointSize += 10
font = font.Bold()
st.SetFont(font)
# and create a sizer to manage the layout of child widgets
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(st, wx.SizerFlags().Border(wx.TOP|wx.LEFT, 25))
panel.SetSizer(sizer)
def makeMenuBar(self):
# Make a file menu with Hello and Exit items
fileMenu = wx.Menu()
# The "\t..." syntax defines an accelerator key that also triggers
# the same event
openItem = fileMenu.Append(-1, "&Open...\tCtrl-O",
"Open a data file")
fileMenu.AppendSeparator()
# When using a stock ID we don't need to specify the menu item's
# label
exitItem = fileMenu.Append(wx.ID_EXIT)
# Now a help menu for the about item
helpMenu = wx.Menu()
aboutItem = helpMenu.Append(wx.ID_ABOUT)
# Now a view menu for the view item
# viewMenu = wx.Menu()
# aboutItem = helpMenu.Append(wx.ID_VIEW)
# Make the menu bar and add the two menus to it. The '&' defines
# that the next letter is the "mnemonic" for the menu item. On the
# platforms that support it those letters are underlined and can be
# triggered from the keyboard.
menuBar = wx.MenuBar()
menuBar.Append(fileMenu, "&File")
menuBar.Append(helpMenu, "&Help")
# menuBar.Append(viewMenu, "&View")
# Give the menu bar to the frame
self.SetMenuBar(menuBar)
# Finally, associate a handler function with the EVT_MENU event for
# each of the menu items. That means that when that menu item is
# activated then the associated handler function will be called.
self.Bind(wx.EVT_MENU, self.OnOpen, openItem)
self.Bind(wx.EVT_MENU, self.OnExit, exitItem)
self.Bind(wx.EVT_MENU, self.OnAbout, aboutItem)
def OnExit(self, event):
self.Close(True)
def OnAbout(self, event):
wx.MessageBox("This is a simple Telemetry software project.",
wx.OK|wx.ICON_INFORMATION)
def drawBrakeThrottlePlot():
data1 = PolyLine([time, brake_p], legend='Brake Pressure (%)', colour='red', width='1')
data2 = PolyLine([time, throttle], legend='Throttle (%)', colour='green', width='1')
return PlotGraphics([data1, data2], "Real Time Brake Pressure and Throttle", "Time (ms)", "Relative Value (%)")
def OnOpen(self, event):
# Create the file dialog
with wx.FileDialog(self, "Open Data file", wildcard="text files (*.txt)|*.txt",
style=wx.FD_OPEN | wx.FD_FILE_MUST_EXIST) as fileDialog:
if fileDialog.ShowModal() == wx.ID_CANCEL:
return # the user changed their mind
# Proceed loading the file chosen by the user
pathname = fileDialog.GetPath()
try:
with open(pathname, 'r') as file:
self.OpenData(file)
except IOError:
wx.LogError("Cannot open file '%s'." % pathname)
def OpenData(self, file):
data = file.readlines() # On assigne à L toutes les lignes du fichier
nb_lignes = len(data) # On assigne à nb_lignes la longueur de L
file.close()
for i in range(nb_lignes):
data[i] = data[i].strip('\n')
temp = data[i].split()
time.append(float(temp[0]))
speed.append((float(temp[8])+float(temp[9]))*r/2)
distance.append(speed[i]*1/1000) # Ici 1/1000 correspond à la fréquence d'échantillonage, modifiable en fx du capteur
brake_p.append(float(temp[1]))
throttle.append(float(temp[2]))
g_x.append(float(temp[3]))
g_y.append(float(temp[4]))
g_z.append(float(temp[5]))
gps_x.append(float(temp[6]))
gps_y.append(float(temp[7]))
omega_fl.append(float(temp[8]))
omega_fr.append(float(temp[9]))
# Remove the text on the panel
for child in self.GetChildren():
child.Destroy()
# create a panel and add it to the main window
panel = wx.Panel(self)
self.sizer = wx.BoxSizer(wx.VERTICAL)
self.sizer.Add(panel, 1, wx.EXPAND)
self.SetSizer(self.sizer)
# Create the plot
self.canvas = PlotCanvas(panel)
self.canvas.Draw(self.drawBrakeThrottlePlot)
self.sizer.Add(self.canvas, 1, wx.EXPAND)
self.sizer.Add(self.createControls(panel), 0, wx.EXPAND)
self.sizer.Add((-1, 10))
self.sizer.Add(self.createButtonBar(panel), 0, wx.EXPAND)
self.SetSizer(self.sizer)
self.sizer.Fit(self)
def createControls(self, panel):
box = wx.StaticBox(panel, -1, 'Data')
sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
grid = wx.GridBagSizer(5, 5)
txt1 = wx.StaticText(panel, -1, 'Time (s)')
grid.Add(txt1, (1, 0))
self.tc1 = wx.TextCtrl(panel, -1, '', size=(80, -1))
grid.Add(self.tc1, (1, 1))
txt2 = wx.StaticText(panel, -1, 'Speed (km/h)')
grid.Add(txt2, (2, 0))
self.tc2 = wx.TextCtrl(panel, -1, '', size=(80, -1))
grid.Add(self.tc2, (2, 1))
txt3 = wx.StaticText(panel, -1, 'RPM')
grid.Add(txt3, (3, 0))
self.tc3 = wx.TextCtrl(panel, -1, '', size=(80, -1))
grid.Add(self.tc3, (3, 1))
txt4 = wx.StaticText(panel, -1, 'Brake pressure')
grid.Add(txt4, (4, 0))
self.tc4 = wx.TextCtrl(panel, -1, '', size=(80, -1))
grid.Add(self.tc4, (4, 1))
txt5 = wx.StaticText(panel, -1, 'Throttle position')
grid.Add(txt5, (5, 0))
self.tc5 = wx.TextCtrl(panel, -1, '', size=(80, -1))
grid.Add(self.tc5, (5, 1))
sizer.Add(grid, 0, wx.ALL, 10)
return sizer
def createButtonBar(self, panel):
"""
Create the buttons at the bottom of the panel
"""
sizer = wx.BoxSizer(wx.HORIZONTAL)
self.zoomInButton = wx.Button(panel, -1, "Zoom In")
self.Bind(wx.EVT_BUTTON, self.OnZoomIn, self.zoomInButton)
sizer.Add(self.zoomInButton, 0, wx.LEFT | wx.RIGHT, 10)
self.zoomOutButton = wx.Button(panel, -1, "Zoom Out")
self.Bind(wx.EVT_BUTTON, self.OnZoomOut, self.zoomOutButton)
sizer.Add(self.zoomOutButton, 0, wx.LEFT | wx.RIGHT, 10)
self.panLeftButton = wx.Button(panel, -1, "Pan Left")
self.Bind(wx.EVT_BUTTON, self.OnPanLeft, self.panLeftButton)
sizer.Add(self.panLeftButton, 0, wx.LEFT | wx.RIGHT, 10)
self.panRightButton = wx.Button(panel, -1, "Pan Right")
self.Bind(wx.EVT_BUTTON, self.OnPanRight, self.panRightButton)
sizer.Add(self.panRightButton, 0, wx.LEFT | wx.RIGHT, 10)
self.resetButton = wx.Button(panel, -1, "Reset")
self.Bind(wx.EVT_BUTTON, self.OnReset, self.resetButton)
sizer.Add(self.resetButton, 0, wx.LEFT | wx.RIGHT, 10)
self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateUI, self.resetButton)
return sizer
def OnZoomIn(self, event):
self.canvas.Zoom(1.2)
event.Skip()
def OnZoomOut(self, event):
self.canvas.Zoom(1/1.2)
event.Skip()
def OnPanLeft(self, event):
self.canvas.Move(-0.1, 0)
event.Skip()
def OnPanRight(self, event):
self.canvas.Move(0.1, 0)
event.Skip()
def OnReset(self, event):
self.canvas.Reset()
event.Skip()
def OnUpdateUI(self, event):
if self.canvas.CanReset():
self.resetButton.Enable(True)
else:
self.resetButton.Enable(False)
if __name__ == '__main__':
app = wx.App()
frame = MainWindow(None, title='Telemetry EFT')
frame.Show()
app.MainLoop()
And here is a link to the example data file : data file

python unittest - with a parameter list generated at runtime

Is there a possibility to give a Unit test a parameter, which is provided at runtime?
For example I've connected 5 COM-Ports to my machine. The test environment should select the correct COM-Port and run its test with it. So whats tested is not the actual python code, the python unit test tool is basically used to verify the communication established with by a python script. Depending on initial communication a number of tests with according parameters (e.g. the comport used) should be selected and added to the batch ( test suite ).
In the next step I want to iterate over an array containing COM-Ports and other optiones.
There is a decorator #parametrized. This solution looks nice and invokes the test like desired. But it is not possible, to use this at run time. The decorator is initiated when the script is loaded. The only workaround known to me is to use a global variable to pass the COM-Port to the TestCase. The tests then must be invoked by a test runner.
To sum up:
Is there a possibility to parametrize a test at run time?
This then could also be added to a testsuite to have a list of same tests only differ in their parameters.
Or an other alternative would be to assign the parameter in the setUpClass() and have anyhow to run several tests again, but with other parameters. Probably this is possible?
So, how do I set up tests with parameter in python with unit test during runtime?
Well the only way to find out if the COM port is correct is by communicating with it. What kind of COM port are we talking about? A 3D printer for example will send periodic commands signaling that it is ready for use, you could use this to detect if there is a 3D printer connected. In python you can easily get a list of available COM ports and try to connect to one of them. I once wrote an interface that could connect to any of an automatically generated list of available COM ports. Maybe you can use parts of it to complete your project:
import math
import serial
import wx
import threading
class MainFrame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None, title = "Hydroponics controller")
self.comport = ""
self.baudrate = 0
self.ser = serial.Serial()
self.p = wx.Panel(self)
nb = Notebook(self)
tab1 = connectionTab(nb)
tab2 = ControllerTab(nb)
nb.AddPage(tab1, "Connection")
nb.AddPage(tab2, "Controller")
sizer = wx.BoxSizer()
sizer.Add(nb, 1, wx.EXPAND)
self.p.SetSizer(sizer)
class Notebook(wx.Notebook):
def __init__(self, parent):
wx.Notebook.__init__(self, parent.p)
self.ser = parent.ser
class connectionTab(wx.Panel):
def __init__(self, parent):
wx.Panel.__init__(self, parent)
self.p = parent
comLabel = wx.StaticText(self, -1, "Serial port", pos = wx.Point(10, 10), size = wx.Size(64, 20))
self.comList = wx.ListBox(self, size = wx.Size(64, 128), choices = [], pos = wx.Point(10, 40), style = wx.LB_SINGLE)
baudrateLabel = wx.StaticText(self, -1, "Baudrate", pos = wx.Point(84, 10), size = wx.Size(64, 20))
self.baudrateList = wx.ListBox(self, size = wx.Size(64, 128), choices = ["9600", "115200", "250000"], pos = wx.Point(84, 40), style = wx.LB_SINGLE)
self.baudrateList.SetSelection(1)
self.refreshButton = wx.Button(self, -1, "Refresh", pos = wx.Point(158, 40))
self.refreshButton.Bind(wx.EVT_BUTTON, self.refreshButton_clicked)
self.connectButton = wx.Button(self, -1, "Connect", pos = wx.Point(158, 70))
self.connectButton.Bind(wx.EVT_BUTTON, self.connectButton_clicked)
self.statusLabel = wx.StaticText(self, -1, "", pos = wx.Point(158, 100))
self.refreshDevices()
def refreshButton_clicked(self, event):
self.refreshDevices()
def connectButton_clicked(self, event):
try:
self.p.ser = serial.Serial(self.comList.GetStringSelection(), self.baudrateList.GetStringSelection())
self.statusLabel.SetLabel("Connection succesful.")
except serial.serialutil.SerialException:
self.statusLabel.SetLabel("Connection failed.")
def refreshDevices(self):
self.availableDevices = []
self.comList.Clear()
for i in range(0,256):
try:
tmp = serial.Serial("COM{}".format(i))
self.comList.Append("COM{}".format(i))
except serial.serialutil.SerialException:
continue
if(self.comList.GetCount()):
self.comList.SetSelection(0)
class ControllerTab(wx.Panel):
def __init__(self, parent):
wx.Panel.__init__(self, parent)
self.parent = parent
self.threadStopped = True
self.t = threading.Thread(target = self.runSequence)
self.t.start()
ROWS = 3
ROWS_POS = [40, 370, 700]
COLUMNS = 10
COLUMNS_POS = [0, 88, 176, 264, 352, 440, 528, 616, 704, 792]
self.commandList = []
self.buttonList = []
for i in range(0, COLUMNS):
for j in range(0, ROWS):
self.buttonList.append(PlantButton(self, COLUMNS_POS[i], ROWS_POS[j], wx.Point(i * 110 + 10, j * 30 + 10)))
self.homeAllButton = wx.Button(self, -1, "Home all", pos = wx.Point(10, ROWS * 30 + 10))
self.homeAllButton.Bind(wx.EVT_BUTTON, self.homeAllButton_clicked)
self.dwellButton = wx.Button(self, -1, "Dwell 1s", pos = wx.Point(10, (ROWS + 1) * 30 + 10))
self.dwellButton.Bind(wx.EVT_BUTTON, self.dwellButton_clicked)
self.commandListBox = wx.ListBox(self, size = wx.Size(192, 512), choices = [], pos = wx.Point(10, (ROWS + 2) * 30 + 10))
self.startSequenceButton = wx.Button(self, -1, "Start sequence", pos = wx.Point(212, (ROWS + 2) * 30 + 10))
self.startSequenceButton.Bind(wx.EVT_BUTTON, self.startSequenceButton_clicked)
self.saveFileButton = wx.Button(self, -1, "Save to file", pos = wx.Point(212, (ROWS + 3) * 30 + 10))
self.saveFileButton.Bind(wx.EVT_BUTTON, self.saveFileButton_clicked)
self.deleteCommandButton = wx.Button(self, -1, "Delete selected command", pos = wx.Point(212, (ROWS + 4) * 30 + 10))
self.deleteCommandButton.Bind(wx.EVT_BUTTON, self.deleteCommandButton_clicked)
def homeAllButton_clicked(self, event):
self.commandList.append("G92 X200\nG1 X0 F6000\nG28 XYZ\n")
self.commandListBox.Append("Home all")
def dwellButton_clicked(self, event):
self.commandList.append("G4 P1000\n")
self.commandListBox.Append("Dwell for 1 second")
def startSequenceButton_clicked(self, event):
self.threadStopped = False
def saveFileButton_clicked(self, event):
file = open("sequence.gcode", "w")
for i in range(0, len(self.commandList)):
file.write(self.commandList[i])
file.close()
def deleteCommandButton_clicked(self, event):
index = self.commandListBox.GetSelection()
if(index == wx.NOT_FOUND):
return
self.commandList.pop(index)
self.commandListBox.Delete(index)
if(index == 0):
self.commandListBox.SetSelection(0)
else:
self.commandListBox.SetSelection(index - 1)
def runSequence(self):
while True:
if(self.threadStopped == False):
sequenceLength = len(self.commandList)
index = 0
self.parent.ser.write("G92 X100\nG1 X0 F6000\nM340 P3 S2000\nG28 XYZ\n")
while((index < sequenceLength) & (self.threadStopped == False)):
data = self.parent.ser.readline()
if(len(data) != 0):
print "READ: {}".format(data),
if(data == "ok 0\r\n"):
print "SENT: {}".format(self.commandList[index]),
self.parent.ser.write(self.commandList[index])
index += 1
print "Stopped"
self.threadStopped = True
class PlantButton:
def __init__(self, parent, x, y, buttonPos):
self.parent = parent
self.x = x
self.y = y
self.buttonPos = buttonPos
self.button = wx.Button(self.parent, -1, "({}, {})".format(self.x, self.y), pos = self.buttonPos)
self.button.Bind(wx.EVT_BUTTON, self.button_clicked)
def button_clicked(self, event):
self.parent.commandList.append("G1 X{} Y{} F6000\n".format(self.y, self.x))
self.parent.commandList.append("G1 Z70 F6000\nG4 P1000\nM340 P3 S2500\nG4 P500\nM340 P3 S2468\nG4 P1000\nG91\nG1 X-40 F6000\nG90\nG1 Z0 F6000\n")
self.parent.commandList.append("G1 X700 F6000\nG4 P1000\nM340 P3 S2000\n")
self.parent.commandListBox.Append("Go to position ({}, {})\n".format(self.x, self.y))
if __name__ == "__main__":
app = wx.App()
MainFrame().Show()
app.MainLoop()

Fitting matplotlib figure to wxpnel

I am trying to display a plot in a wxpanel so that when initialized it has 5 pixels gap from left top and right edges.
I tried the code below but it looks like when the plot is created it sticks right to the right edge of the panel. After resizing the gap appear.
# -*- coding: utf-8 -*-
import wx
#import pandas as pd
import matplotlib.pyplot as plt
from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as FigureCanvas
from relpermtable import RelPermTable as RelPermCl
class KrPanel(wx.Panel):
def __init__(self, parent):
super().__init__(parent)
main_sizer = wx.BoxSizer(wx.VERTICAL)
self.list_ctrl = wx.ListCtrl(
self, size = (-1, 300),
style = wx.LC_REPORT | wx.BORDER_SUNKEN
)
self.list_ctrl.InsertColumn(0, 'Sw', width=100)
self.list_ctrl.InsertColumn(1, 'Krw', width=100)
self.list_ctrl.InsertColumn(2, 'Krg', width=100)
self.list_ctrl.InsertColumn(3, 'Pc', width=100)
main_sizer.Add(self.list_ctrl, 0, wx.ALL | wx.EXPAND, 5)
self.SetSizer(main_sizer)
def load_KrPc_data(self, in_dfr):
for index, row in in_dfr.iterrows():
self.list_ctrl.InsertItem(index, str(row["Sg"]))
self.list_ctrl.SetItem(index, 1, str(row["Krg"]))
self.list_ctrl.SetItem(index, 2, str(row["Krw"]))
self.list_ctrl.SetItem(index, 3, str(row["Pc"]))
class PlotPanel(wx.Panel):
def __init__(self, parent):
super().__init__(parent)
def PlotKrPcData(self, df_in, in_swco, in_sgco):
right_sizer = wx.BoxSizer(wx.VERTICAL)
self.fig, self.ax1 = plt.subplots() # figsize=(5,5)
# self.ax2 = self.ax1.twinx()
self.ax1.plot(df_in['Sg'], df_in['Krg'], 'r-')
self.ax1.plot(df_in['Sg'], df_in['Krw'], 'g-')
# self.ax2.plot(new_df['Sg'], new_df['Pc'], 'b-')
self.ax1.plot((1-in_swco), 0, 'go')
self.ax1.annotate('1-SWL', ((1-in_swco), 0.05))
self.ax1.plot((in_sgco), 0, 'go', label = 'SGL')
self.ax1.annotate('SGL', (in_sgco, 0.05))
self.canvas = FigureCanvas(self, -1, self.fig)
right_sizer.Add(self.canvas, 0, wx.ALL | wx.EXPAND, 5)
self.SetSizer(right_sizer)
class KrFrame(wx.Frame):
def __init__(self):
super().__init__(parent=None,
title='Gas Relative Permeability Editor', size=(900, 800))
self.sp = wx.SplitterWindow(self)
self.panel01 = KrPanel(self.sp)
self.panel02 = PlotPanel(self.sp)
self.sp.SplitVertically(self.panel01, self.panel02, 450)
self.create_menu()
self.Show()
def create_menu(self):
menu_bar = wx.MenuBar()
file_menu = wx.Menu()
open_file_menu_item = file_menu.Append(
wx.ID_ANY, 'Open File', 'Open a Relative Permeability File'
)
exit_menu_item = file_menu.Append(
wx.ID_EXIT, "Exit", "Exit the application"
)
menu_bar.Append(file_menu, '&File')
self.Bind(
event = wx.EVT_MENU,
handler = self.on_open_file,
source = open_file_menu_item
)
self.Bind(
event = wx.EVT_MENU,
handler = self.on_exit,
source = exit_menu_item
)
self.SetMenuBar(menu_bar)
def on_open_file(self, event):
title = "Choose a Relative Permeability file:"
dlg = wx.FileDialog(self, title, "", "",
"Eclipse include files (*.INC) | *.INC", style = wx.FD_DEFAULT_STYLE)
if dlg.ShowModal() == wx.ID_OK:
object = RelPermCl(dlg.GetPath())
new_df = object.load_KrPc_data()
new_sgco = object.calc_sgco()
new_swco = object.calc_swco()
# new_sgmax = object.calc_sgmax()
# new_swmax = object.calc_swmax()
# new_sgcr = object.calc_sgcr()
# new_swcr = object.calc_swcr()
self.panel01.load_KrPc_data(new_df)
self.panel02.PlotKrPcData(new_df, new_sgco, new_swco)
# print(new_df.head())
dlg.Destroy()
def on_exit(self, e):
self.Close()
if __name__ == '__main__':
app = wx.App(False)
frame = KrFrame()
app.MainLoop()
del app
I'd like to have 5 pixels gap on the right of the plot when the plot is created. But somehow the gap is created only after resize. Is there a way to set plot size let's say to the size of the panel independently of panel size and specify border sizes?
Try to put a frame.SendSizeEvent() before the Show call. If it doesn’t work, try with wx.CallAfter(frame.SendSizeEvent)

Multi lines realtime plotting

I would like to plot multi-lines in Python in a real-time manner though I'm just too new to this language.
I have found some codes as example to work fine but can only get one line plotted. Would someone help me with multi-lines please? Also, I need to adjust the line width, color, etc. of the lines.
The code is as follows:
# -*- coding: utf-8 -*-
"""
This demo demonstrates how to draw a dynamic mpl (matplotlib)
plot in a wxPython application.
It allows "live" plotting as well as manual zooming to specific
regions.
Both X and Y axes allow "auto" or "manual" settings. For Y, auto
mode sets the scaling of the graph to see all the data points.
For X, auto mode makes the graph "follow" the data. Set it X min
to manual 0 to always see the whole data from the beginning.
Note: press Enter in the 'manual' text box to make a new value
affect the plot.
Eli Bendersky (eliben#gmail.com)
License: this code is in the public domain
Last modified: 31.07.2008
"""
import os
import pprint
import random
import sys
import wx
# The recommended way to use wx with mpl is with the WXAgg
# backend.
#
import matplotlib
matplotlib.use('WXAgg')
from matplotlib.figure import Figure
from matplotlib.backends.backend_wxagg import \
FigureCanvasWxAgg as FigCanvas, \
NavigationToolbar2WxAgg as NavigationToolbar
import numpy as np
import pylab
class DataGen(object):
""" A silly class that generates pseudo-random data for
display in the plot.
"""
def __init__(self, init=50):
self.data = self.init = init
def next(self):
self._recalc_data()
return self.data
def _recalc_data(self):
delta = random.uniform(-0.5, 0.5)
r = random.random()
if r > 0.9:
self.data += delta * 15
elif r > 0.8:
# attraction to the initial value
delta += (0.5 if self.init > self.data else -0.5)
self.data += delta
else:
self.data += delta
class BoundControlBox(wx.Panel):
""" A static box with a couple of radio buttons and a text
box. Allows to switch between an automatic mode and a
manual mode with an associated value.
"""
def __init__(self, parent, ID, label, initval):
wx.Panel.__init__(self, parent, ID)
self.value = initval
box = wx.StaticBox(self, -1, label)
sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
self.radio_auto = wx.RadioButton(self, -1,
label="Auto", style=wx.RB_GROUP)
self.radio_manual = wx.RadioButton(self, -1,
label="Manual")
self.manual_text = wx.TextCtrl(self, -1,
size=(35,-1),
value=str(initval),
style=wx.TE_PROCESS_ENTER)
self.Bind(wx.EVT_UPDATE_UI, self.on_update_manual_text, self.manual_text)
self.Bind(wx.EVT_TEXT_ENTER, self.on_text_enter, self.manual_text)
manual_box = wx.BoxSizer(wx.HORIZONTAL)
manual_box.Add(self.radio_manual, flag=wx.ALIGN_CENTER_VERTICAL)
manual_box.Add(self.manual_text, flag=wx.ALIGN_CENTER_VERTICAL)
sizer.Add(self.radio_auto, 0, wx.ALL, 10)
sizer.Add(manual_box, 0, wx.ALL, 10)
self.SetSizer(sizer)
sizer.Fit(self)
def on_update_manual_text(self, event):
self.manual_text.Enable(self.radio_manual.GetValue())
def on_text_enter(self, event):
self.value = self.manual_text.GetValue()
def is_auto(self):
return self.radio_auto.GetValue()
def manual_value(self):
return self.value
class GraphFrame(wx.Frame):
""" The main frame of the application
"""
title = 'Demo: dynamic matplotlib graph'
#修改下面self.redraw_timer.Start(100)数值影响plot下一个数据点的速度,越大速度越慢
def __init__(self):
wx.Frame.__init__(self, None, -1, self.title)
self.datagen = DataGen()
self.data = [self.datagen.next()]
self.paused = False
self.create_menu()
self.create_status_bar()
self.create_main_panel()
self.redraw_timer = wx.Timer(self)
self.Bind(wx.EVT_TIMER, self.on_redraw_timer, self.redraw_timer)
self.redraw_timer.Start(100)
def create_menu(self):
self.menubar = wx.MenuBar()
menu_file = wx.Menu()
m_expt = menu_file.Append(-1, "&Save plot\tCtrl-S", "Save plot to file")
self.Bind(wx.EVT_MENU, self.on_save_plot, m_expt)
menu_file.AppendSeparator()
m_exit = menu_file.Append(-1, "E&xit\tCtrl-X", "Exit")
self.Bind(wx.EVT_MENU, self.on_exit, m_exit)
self.menubar.Append(menu_file, "&File")
self.SetMenuBar(self.menubar)
def create_main_panel(self):
self.panel = wx.Panel(self)
self.init_plot()
self.canvas = FigCanvas(self.panel, -1, self.fig)
self.xmin_control = BoundControlBox(self.panel, -1, "X min", 0)
self.xmax_control = BoundControlBox(self.panel, -1, "X max", 50)
self.ymin_control = BoundControlBox(self.panel, -1, "Y min", 0)
self.ymax_control = BoundControlBox(self.panel, -1, "Y max", 100)
self.pause_button = wx.Button(self.panel, -1, "Pause")
self.Bind(wx.EVT_BUTTON, self.on_pause_button, self.pause_button)
self.Bind(wx.EVT_UPDATE_UI, self.on_update_pause_button, self.pause_button)
self.cb_grid = wx.CheckBox(self.panel, -1,
"Show Grid",
style=wx.ALIGN_RIGHT)
self.Bind(wx.EVT_CHECKBOX, self.on_cb_grid, self.cb_grid)
self.cb_grid.SetValue(True)
self.cb_xlab = wx.CheckBox(self.panel, -1,
"Show X labels",
style=wx.ALIGN_RIGHT)
self.Bind(wx.EVT_CHECKBOX, self.on_cb_xlab, self.cb_xlab)
self.cb_xlab.SetValue(True)
self.hbox1 = wx.BoxSizer(wx.HORIZONTAL)
self.hbox1.Add(self.pause_button, border=5, flag=wx.ALL | wx.ALIGN_CENTER_VERTICAL)
self.hbox1.AddSpacer(20)
self.hbox1.Add(self.cb_grid, border=5, flag=wx.ALL | wx.ALIGN_CENTER_VERTICAL)
self.hbox1.AddSpacer(10)
self.hbox1.Add(self.cb_xlab, border=5, flag=wx.ALL | wx.ALIGN_CENTER_VERTICAL)
self.hbox2 = wx.BoxSizer(wx.HORIZONTAL)
self.hbox2.Add(self.xmin_control, border=5, flag=wx.ALL)
self.hbox2.Add(self.xmax_control, border=5, flag=wx.ALL)
self.hbox2.AddSpacer(24)
self.hbox2.Add(self.ymin_control, border=5, flag=wx.ALL)
self.hbox2.Add(self.ymax_control, border=5, flag=wx.ALL)
self.vbox = wx.BoxSizer(wx.VERTICAL)
self.vbox.Add(self.canvas, 1, flag=wx.LEFT | wx.TOP | wx.GROW)
self.vbox.Add(self.hbox1, 0, flag=wx.ALIGN_LEFT | wx.TOP)
self.vbox.Add(self.hbox2, 0, flag=wx.ALIGN_LEFT | wx.TOP)
self.panel.SetSizer(self.vbox)
self.vbox.Fit(self)
def create_status_bar(self):
self.statusbar = self.CreateStatusBar()
def init_plot(self):
self.dpi = 100
self.fig = Figure((3.0, 3.0), dpi=self.dpi)
self.axes = self.fig.add_subplot(111)
self.axes.set_axis_bgcolor('gainsboro')
self.axes.set_title('Very important random data', size=12)
pylab.setp(self.axes.get_xticklabels(), fontsize=8)
pylab.setp(self.axes.get_yticklabels(), fontsize=8)
# plot the data as a line series, and save the reference
# to the plotted line series
#
self.plot_data = self.axes.plot(
self.data,
linewidth=1,
color=(1, 1, 0),
)[0]
# 修改下面1000可以修改图标put出来的数据量
def draw_plot(self):
""" Redraws the plot
"""
# when xmin is on auto, it "follows" xmax to produce a
# sliding window effect. therefore, xmin is assigned after
# xmax.
#
if self.xmax_control.is_auto():
xmax = len(self.data) if len(self.data) > 1000 else 1000
else:
xmax = int(self.xmax_control.manual_value())
if self.xmin_control.is_auto():
xmin = xmax - 1000
else:
xmin = int(self.xmin_control.manual_value())
# for ymin and ymax, find the minimal and maximal values
# in the data set and add a mininal margin.
#
# note that it's easy to change this scheme to the
# minimal/maximal value in the current display, and not
# the whole data set.
#
if self.ymin_control.is_auto():
ymin = round(min(self.data), 0) - 1
else:
ymin = int(self.ymin_control.manual_value())
if self.ymax_control.is_auto():
ymax = round(max(self.data), 0) + 1
else:
ymax = int(self.ymax_control.manual_value())
self.axes.set_xbound(lower=xmin, upper=xmax)
self.axes.set_ybound(lower=ymin, upper=ymax)
# anecdote: axes.grid assumes b=True if any other flag is
# given even if b is set to False.
# so just passing the flag into the first statement won't
# work.
#
if self.cb_grid.IsChecked():
self.axes.grid(True, color='gray')
else:
self.axes.grid(False)
# Using setp here is convenient, because get_xticklabels
# returns a list over which one needs to explicitly
# iterate, and setp already handles this.
#
pylab.setp(self.axes.get_xticklabels(),
visible=self.cb_xlab.IsChecked())
self.plot_data.set_xdata(np.arange(len(self.data)))
self.plot_data.set_ydata(np.array(self.data))
self.canvas.draw()
def on_pause_button(self, event):
self.paused = not self.paused
def on_update_pause_button(self, event):
label = "Resume" if self.paused else "Pause"
self.pause_button.SetLabel(label)
def on_cb_grid(self, event):
self.draw_plot()
def on_cb_xlab(self, event):
self.draw_plot()
def on_save_plot(self, event):
file_choices = "PNG (*.png)|*.png"
dlg = wx.FileDialog(
self,
message="Save plot as...",
defaultDir=os.getcwd(),
defaultFile="plot.png",
wildcard=file_choices,
style=wx.SAVE)
if dlg.ShowModal() == wx.ID_OK:
path = dlg.GetPath()
self.canvas.print_figure(path, dpi=self.dpi)
self.flash_status_message("Saved to %s" % path)
def on_redraw_timer(self, event):
# if paused do not add data, but still redraw the plot
# (to respond to scale modifications, grid change, etc.)
#
if not self.paused:
self.data.append(self.datagen.next())
self.draw_plot()
def on_exit(self, event):
self.Destroy()
def flash_status_message(self, msg, flash_len_ms=1500):
self.statusbar.SetStatusText(msg)
self.timeroff = wx.Timer(self)
self.Bind(
wx.EVT_TIMER,
self.on_flash_status_off,
self.timeroff)
self.timeroff.Start(flash_len_ms, oneShot=True)
def on_flash_status_off(self, event):
self.statusbar.SetStatusText('')
if __name__ == '__main__':
app = wx.PySimpleApp()
app.frame = GraphFrame()
app.frame.Show()
app.MainLoop()
You may find wxmplot (http://newville.github.io/wxmplot/) useful for this. It exposes and simplifies many aspects of using matplotlib with wxPython. It supports setting line attributes either programmatically or from a GUI panel for each plot. The demo includes a doing relatively fast "updating" for real-time plotting (10 fps or better, usually depending on hardware).

Transparent panel doesn't updates its background after being moved/dragged in wxPython

I am working with python v2.7 and wxPython v3.0 on Windows 8 OS.
The code provided below simply creates a transparent panel named as myPanel that contains a button. The transparent panel is created on a mainPanel which contains an image as a background.
The transparent panel can be dragged around in the frame.
Problem: After dragging the transparent panel I observed that the background of the transparent panel is not updated automatically. How to update it automatically? How ever if I minimize the gui window and restore it again, the background of the transparent panel is updated automatically! I don't understand the reason of this affect?
I tried using Refresh(), Update() etc. in MouseUp(self, e) method, but unfortunately nothing helped.
Here are the screenshots of the app. The initial state is shown in the image below when the app starts:
After dragging the transparent panel, the background is not updated as shown in the image below:
After minimizing the app window and then restoring it, you'll notice that the background of the transparent panel is updated automatically as shown in the image below:
Code: The image used in the code can be downloaded from here. globe.jpg
import wx
class gui(wx.Frame):
def __init__(self, parent, id, title):
self.d = d = {}
wx.Frame.__init__(self, None, id, title, size=(260,260), style=wx.DEFAULT_FRAME_STYLE ^ wx.RESIZE_BORDER)
statusbar = self.CreateStatusBar()
self.mainPanel = mainPanel = wx.Panel(self)
self.mainSizer = mainSizer = wx.BoxSizer(wx.VERTICAL)
self.myPanel = myPanel = wx.Panel(mainPanel, -1, style=wx.TRANSPARENT_WINDOW, size=(80,80))
button1 = wx.Button(myPanel, -1, size=(30,30), pos=(10,10))
button1.SetBackgroundColour('#fff111')
mainSizer.Add(myPanel, 0, wx.ALL, 0)
myPanel.Bind(wx.EVT_LEFT_DOWN, self.MouseDown)
myPanel.Bind(wx.EVT_MOTION, self.MouseMove)
myPanel.Bind(wx.EVT_LEFT_UP, self.MouseUp)
image_file = 'globe.jpg'
bmp1 = wx.Image(image_file, wx.BITMAP_TYPE_ANY).ConvertToBitmap()
wx.StaticBitmap(mainPanel, -1, bmp1, (0, 0))
mainPanel.Bind(wx.EVT_MOTION, self.MouseMove)
mainPanel.Bind(wx.EVT_LEFT_UP, self.MouseUp)
mainPanel.SetSizer(mainSizer)
mainPanel.Layout()
def MouseDown(self, e):
o = e.GetEventObject()
sx,sy = self.mainPanel.ScreenToClient(o.GetPositionTuple())
dx,dy = self.mainPanel.ScreenToClient(wx.GetMousePosition())
o._x,o._y = (sx-dx, sy-dy)
self.d['d'] = o
def MouseMove(self, e):
try:
if 'd' in self.d:
o = self.d['d']
x, y = wx.GetMousePosition()
o.SetPosition(wx.Point(x+o._x,y+o._y))
except: pass
def MouseUp(self, e):
try:
if 'd' in self.d: del self.d['d']
except: pass
if __name__=='__main__':
app = wx.App()
frame = gui(parent=None, id=-1, title="Test")
frame.Show()
app.MainLoop()
Thank you for your time!
You can create a custom panel and then draw a portion of the globe on that panel based on where it's located on top of the parent frame. This method "fakes" the transparency. I've included an example below.
import wx
class CustomPanel(wx.Panel):
def __init__(self,parent):
wx.Panel.__init__(self,parent,-1,size=(80,80))
self.Bind(wx.EVT_PAINT, self.OnPaint)
def OnPaint(self, evt):
parentw,parenth = self.GetParent().GetSize()
image = wx.Image('globe.jpg', wx.BITMAP_TYPE_ANY)
x,y = self.GetPosition()
mywidth,myheight = self.GetSize()
if x + mywidth >= parentw:
mywidth = parentw - x
if y + myheight >= parenth:
myheight = parenth - y
drawx = 0
drawy = 0
if x < 0:
drawx = abs(x)
x = 0
if y < 0:
drawy = abs(y)
y = 0
r = wx.Rect(x,y,mywidth,myheight)
try:
image = image.GetSubImage(r)
except:
# rectangle is out of parent
print 'rect ',r ,' is out of parent frame'
return
bitmap = image.ConvertToBitmap()
pdc = wx.PaintDC(self)
pdc.DrawBitmap(bitmap, drawx, drawy)
class gui(wx.Frame):
def __init__(self, parent, id, title):
self.d = d = {}
wx.Frame.__init__(self, None, id, title, size=(260,260), style=wx.DEFAULT_FRAME_STYLE | wx.RESIZE_BORDER | wx.CLIP_CHILDREN)
statusbar = self.CreateStatusBar()
self.mainPanel = mainPanel = wx.Panel(self)
self.mainSizer = mainSizer = wx.BoxSizer(wx.VERTICAL)
#self.myPanel = myPanel = wx.Panel(mainPanel, -1, style=wx.TRANSPARENT_WINDOW, size=(80,80))
self.myPanel = myPanel = CustomPanel(mainPanel)
button1 = wx.Button(myPanel, -1, size=(30,30), pos=(10,10))
button1.SetBackgroundColour('#fff111')
button2 = wx.Button(myPanel, -1, size=(30,30), pos=(40,40))
button2.SetBackgroundColour('#fff111')
mainSizer.Add(myPanel, 0, wx.ALL, 0)
myPanel.Bind(wx.EVT_LEFT_DOWN, self.MouseDown)
myPanel.Bind(wx.EVT_MOTION, self.MouseMove)
myPanel.Bind(wx.EVT_LEFT_UP, self.MouseUp)
image_file = 'globe.jpg'
bmp1 = wx.Image(image_file, wx.BITMAP_TYPE_ANY).ConvertToBitmap()
wx.StaticBitmap(mainPanel, -1, bmp1, (0, 0))
mainPanel.Bind(wx.EVT_MOTION, self.MouseMove)
mainPanel.Bind(wx.EVT_LEFT_UP, self.MouseUp)
mainPanel.SetSizer(mainSizer)
mainPanel.Layout()
def MouseDown(self, e):
o = e.GetEventObject()
sx,sy = self.mainPanel.ScreenToClient(o.GetPositionTuple())
dx,dy = self.mainPanel.ScreenToClient(wx.GetMousePosition())
o._x,o._y = (sx-dx, sy-dy)
self.d['d'] = o
def MouseMove(self, e):
try:
if 'd' in self.d:
o = self.d['d']
x, y = wx.GetMousePosition()
o.SetPosition(wx.Point(x+o._x,y+o._y))
self.myPanel.Refresh()
except: pass
def MouseUp(self, e):
try:
if 'd' in self.d: del self.d['d']
except: pass
if __name__=='__main__':
app = wx.App()
frame = gui(parent=None, id=-1, title="Test")
frame.Show()
app.MainLoop()

Categories