How do I change the style of a toggle button in wxPython? - user-interface

I never figured out how to use the style parameter. Can someone tell me how to use it to make nicer toggle buttons? Or if you can't use it directly, is there a way to do it manually?

Try something like this:
import wx
class MyForm(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None, wx.ID_ANY, "Toggle")
panel = wx.Panel(self, wx.ID_ANY)
self.button = wx.ToggleButton(panel, label="Press Me")
self.button.Bind(wx.EVT_TOGGLEBUTTON, self.onToggle)
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(self.button, 0, wx.ALL, 5)
panel.SetSizer(sizer)
def onToggle(self, event):
if self.button.GetValue() == True:
self.button.SetLabel("On")
else:
self.button.SetLabel("Off")
if __name__ == "__main__":
app = wx.App(False)
frame = MyForm()
frame.Show()
app.MainLoop()

Related

Best approach / Design pattern for communication between a GUI class and a Worker class

consider the following pseudo code:
class gui():
...
def main(self):
btn = button(on_click=start_worker) #on button click call worker.start_worker()
def show_messagebox(self):
messagebox.show("event_occurred")
class worker():
...
def start_worker(self):
self.run()
def event_occurred(self):
#call gui.show_messagebox
those two classes are threads which calls each other functions, what is the best design pattern / coding approach for communicating between those two classes?
for example:
def app():
def main():
g = gui()
w = worker()
or
def gui():
def main():
w = worker()
or
def worker():
def main():
g = gui()
or something else..
please elaborate your answer.
Thanks.

How to draw on pixmap - PySide6 [duplicate]

Image does not show up when trying to draw a rectangle over QLabelimage. I want to be able to draw a rectangle over the photo and be able to keep the rectangle/hide it. Here's what I tried after checking suggestions here:
How to draw a rectangle and adjust its shape by drag and drop in PyQt5
from PyQt5.QtGui import QPixmap, QImage, QPainter, QBrush, QColor
from PyQt5.QtWidgets import QMainWindow, QApplication, QDesktopWidget, QVBoxLayout, QWidget, QLabel
from PyQt5.QtCore import QPoint, QRect
import sys
import cv2
class TestRect(QLabel):
def __init__(self):
super().__init__()
self.begin = QPoint()
self.end = QPoint()
def paintEvent(self, event):
qp = QPainter(self)
br = QBrush(QColor(100, 10, 10, 40))
qp.setBrush(br)
qp.drawRect(QRect(self.begin, self.end))
def mousePressEvent(self, event):
self.begin = event.pos()
self.end = event.pos()
self.update()
def mouseMoveEvent(self, event):
self.end = event.pos()
self.update()
def mouseReleaseEvent(self, event):
self.begin = event.pos()
self.end = event.pos()
self.update()
class TestWindow(QMainWindow):
def __init__(self):
super().__init__()
self.current_image = None
win_rectangle = self.frameGeometry()
center_point = QDesktopWidget().availableGeometry().center()
win_rectangle.moveCenter(center_point)
self.move(win_rectangle.topLeft())
self.main_layout = QVBoxLayout()
self.central_widget = QWidget(self)
self.test_image()
self.show()
def test_image(self):
self.central_widget.setLayout(self.main_layout)
self.setCentralWidget(self.central_widget)
image = TestRect()
self.main_layout.addWidget(image)
uploaded = cv2.imread('test.jpg')
resized = cv2.resize(uploaded, (500, 500))
height, width = 500, 500
self.current_image = QImage(resized, height, width, QImage.Format_RGB888)
image.setPixmap(QPixmap(self.current_image))
if __name__ == '__main__':
test = QApplication(sys.argv)
test_window = TestWindow()
sys.exit(test.exec_())
If you override a method without calling the parent's implementation through super then the previous behavior will not be used, and that is what happens in your case: The normal behavior of QLabel is to draw but to override and not to call super it was eliminated . The solution is:
def paintEvent(self, event):
super().paintEvent(event)
qp = QPainter(self)
br = QBrush(QColor(100, 10, 10, 40))
qp.setBrush(br)
qp.drawRect(QRect(self.begin, self.end))

wx python image quality gets degraded

In my application I allow the user to resize certain images. All of the images are read on opening the application and held in a dictionary.
My solution allows for resizing, but as the image is Rescaled the quality degrades. I would like to do something like a deepcopy on the image before it is resized, but I don't seem to able to achieve it.
(I know the code seems convoluted, but I have extracted it from a much larger and more complex set of code)
I am just using any old png file as the image source.
import wx
import copy
class MainFrame(wx.Frame):
IMAGE_SIZE = ['large', 'medium', 'small']
IMAGE_NAME = 'question'
def __init__(self, *args, **kwargs):
super(MainFrame, self).__init__(None, *args, **kwargs)
self.Title = 'Test image size'
self.images = self._get_images()
self.panel = MainPanel(self)
sizer = wx.BoxSizer()
sizer.Add(self.panel)
self.SetSizerAndFit(sizer)
self.Centre()
self.Show()
def _get_images(self):
image = wx.Image(self.IMAGE_NAME+'.png')
return {self.IMAGE_NAME: image}
def on_image_size_click(self, event):
size_index = self.panel.image_size.GetSelection()
image_size = self.IMAGE_SIZE[size_index]
self.panel.image.refresh(self.IMAGE_NAME, image_size)
self.Layout()
class MainPanel(wx.Panel):
def __init__(self, parent, *args, **kwargs):
super(MainPanel, self).__init__(parent, *args, **kwargs)
self.images = parent.images
sizer = wx.BoxSizer(wx.HORIZONTAL)
self.image_size = wx.RadioBox(parent=self, label='Image_size',
choices=parent.IMAGE_SIZE,
style=wx.RA_SPECIFY_ROWS)
self.image_size.Bind(wx.EVT_RADIOBOX, parent.on_image_size_click)
self.image = ImagePanel(self, parent.IMAGE_NAME, parent.IMAGE_SIZE[0])
sizer.Add(self.image_size)
sizer.Add(self.image, flag=wx.ALIGN_CENTER)
self.SetSizer(sizer)
class ImagePanel(wx.Panel):
IMAGE_SIZE = {'large': (48, 36), 'medium': (30, 22), 'small': (24, 16)}
def __init__(self, parent, image_name, size, *args, **kwargs):
super(ImagePanel, self).__init__(parent, *args, **kwargs)
self.images = parent.images
self.image_sizer = wx.BoxSizer(wx.HORIZONTAL)
self.refresh(image_name, size)
def refresh(self, image_name, size):
self.clear_sizer(self.image_sizer)
image_size = self.IMAGE_SIZE[size]
image = self.images[image_name]
#image = copy.deepcopy(self.images[image_name])
image.Rescale(image_size[0], image_size[1], wx.IMAGE_QUALITY_HIGH)
bitmap = wx.Bitmap(image)
static_bitmap = wx.StaticBitmap(self, bitmap=bitmap)
self.image_sizer.Add(static_bitmap)
self.SetSizer(self.image_sizer)
#staticmethod
def clear_sizer(sizer):
for child in sizer.GetChildren():
sizer_child = child.GetWindow()
sizer_child.Hide()
sizer.Detach(sizer_child)
if __name__ == '__main__':
"""Run the application."""
screen_app = wx.App()
main_frame = MainFrame()
screen_app.MainLoop()
wx.Image has it's own Copy function, which will work well for your purposes.
image = self.images[image_name]
#image = copy.deepcopy(self.images[image_name])
image = image.Copy()

wxPython dirpickerctrl text box appearing over its own browse button

My wxPython dirPickerCtrl text box is appearing over the top of its browse button.
My code is:
class chooseFolder(wx.DirPickerCtrl):
def __init__(self, *args, **kwargs):
wx.DirPickerCtrl.__init__(self, *args, **kwargs)
dataFolder = chooseFolder(self, -1, message= 'Choose Folder', pos = (55,24),
style= wx.DIRP_DEFAULT_STYLE,
size = (250, 25))
I have tried applying different sizers in that panel to see if that solves it but to no avail.
I am using wx version 4.0.3
EDIT: Below is a minimal code example to demonstrate the problem I am having, shown in the second picture.
import wx
import os
class ButtonFrame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None)
self.panel = wx.Panel(self, -1)
chooseFolder(parent=self,
pos = (10,100),
style= wx.DIRP_DEFAULT_STYLE,
size = (250, 30))
self.Centre()
self.Show()
class chooseFolder(wx.DirPickerCtrl):
def __init__(self, *args, **kwargs):
wx.DirPickerCtrl.__init__(self, *args, **kwargs)
if __name__ == "__main__":
app = wx.App()
ButtonFrame()
app.MainLoop()
picture of text box on top of button
EDIT: Picture of output from minimal code example
Edit based on code sample supplied:
I cannot test on Windows but it looks as if it may be a bug (it works on Linux).
Do you get the same result if you don't sub-class DirPickerCtrl but use it directly? Like this:
import wx
class ButtonFrame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None)
self.panel = wx.Panel(self, -1)
chooseFolder = wx.DirPickerCtrl(self.panel, -1, pos = (10,100), path = "",
style= wx.DIRP_DEFAULT_STYLE,
size = (250, 30))
# chooseFolder(parent=self,
# id = -1,
# pos = (10,100),
# path = "/home",
# style= wx.DIRP_DEFAULT_STYLE)#,
# #size = (250, 30))
self.Centre()
self.Show()
#class chooseFolder(wx.DirPickerCtrl):
# def __init__(self, *args, **kwargs):
# wx.DirPickerCtrl.__init__(self, *args, **kwargs)
if __name__ == "__main__":
app = wx.App()
ButtonFrame()
app.MainLoop()
You mention that you have tried applying sizers to the panel but in the question, there is no reference to a panel at all.
Try playing with the code below and see if it helps.
For simplicity, it relies solely on fixed positions (no sizers).
import wx
import os
class ButtonFrame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self,None)
self.panel = wx.Panel(self, -1)
self.BtnPressHere = wx.Button(self.panel, -1, "Press Here", pos=(10,10))
self.BtnPressHere.Bind(wx.EVT_BUTTON, self.OnPress)
self.Bind(wx.EVT_DIRPICKER_CHANGED, self.DirChange)
self.Centre()
self.Show()
print("Current Dir: ",os.getcwd())
def OnPress(self,event):
dataFolder = chooseFolder(parent=self,
id=-1,
path='/home',
message='Choose Folder',
pos = (10,100),
style= wx.DIRP_DEFAULT_STYLE|wx.DIRP_CHANGE_DIR,
size = (250, 30))
def DirChange(self,event):
print("Dir changed to: ", event.GetPath())
print("Checking Current Dir: ",os.getcwd())
class chooseFolder(wx.DirPickerCtrl):
def __init__(self, *args, **kwargs):
wx.DirPickerCtrl.__init__(self, *args, **kwargs)
if __name__ == "__main__":
app = wx.App()
ButtonFrame()
app.MainLoop()
I think the problem comes from the size given to the constructor. Try setting the height (second parameter of size) to -1 .

Why is wxPython OnPaint method not triggering for wx.lib.scrolledpanel.ScrolledPanel?

First things first, the debugger doesn't touch my breakpoint.
It is set at the first instruction in the OnPaint method in my custom class.
import wx.aui, wx.lib.agw.aui
from wx.lib import platebtn
import wx.lib.scrolledpanel as spanel
class GuiScrolledPanel(spanel.ScrolledPanel):
def __init__(self, *args, **kwargs):
spanel.ScrolledPanel.__init__(self, *args, **kwargs)
self.SetSizer(GuiSchemaSizer())
self.SetupScrolling()
self.caption = "No active schema - Create a new schema or load one "
def OnChildFocus(self, *args, **kwargs):
self.Layout()
self.AdjustScrollbars()
return spanel.ScrolledPanel.OnChildFocus(self, *args, **kwargs)
def updateCaption(self, caption):
self.caption = caption
def OnPaint(self, *args, **kwargs):
some_result = spanel.ScrolledPanel.OnPaint(self, *args, **kwargs)
print 'OnPaint in MyDrawingArea'
dc = wx.PaintDC(self)
dc.BeginDrawing()
if self.BufferBmp != None:
print '...drawing'
dc.DrawBitmap(self.BufferBmp, 0, 0, True)
#should draw smth here, but what's the point when the method isn't even called, heh?
else:
print '...nothing to draw'
dc.EndDrawing()
return some_result
Thx a lot :)
It seems that the OnPaint method mUst be registered with the event wx.EVT_BIND.
self.Bind(wx.EVT_PAINT, self.OnPaint)

Resources