how to overload QToolBar.addAction() method - python-2.7

How to overload any method in PyQt
class Main_Window( QMainWindow):
def __init__(self, parent = None):
super(Main_Window,self).__init__(parent)
self.initUI()
def initUI(self):
dialog_window = QAction( '&Create Plugin', self
dialog_window.triggered.connect(self.showdialog)
toolbar = self.addToolBar('Exit')
# toolbar.addAction(QIcon("plugin0.png"),'',self.showdialog)
I want to overload QToolBar.addAction(self, QIcon icon,callable receiver)
.........
toolbar.addAction(QIcon("plugin0.png"),self.showdialog)
self.setGeometry(300, 300, 300, 200)
self.setWindowTitle('Menubar')
self.show()
def showdialog(self):
d = Dialog_window()
d.exec_()
def main():
app = QApplication(sys.argv)
ex = Main_Window()
sys.exit(app.exec_())

A small quick example...
class MyToolBar( QToolBar ) :
"""Class doc
"""
def __init__( self, parent ) :
"""Class initialiser
"""
QToolBar.__init__( self, parent )
def addAction( self, icn, func ) :
act = QAction( icon, QString(), self )
self.addAction( act )

Related

Undo\Redo with multi items movement QGraphicScene - pyqt5

I have implemented QUndoStack with QGraphicScene and everything is working like charm with individual QGraphicItem movement/rotation, but when it comes to the multi-items movement, I couldn't find any way to do so, since I didn't find any flag/signal that will be emitted after all selected item position has been changed [ NOT DURING].
Here is a sketch code that will represent my goals.
import sys
from typing import Dict
from PyQt5.QtCore import Qt, QPoint
from PyQt5.QtGui import QPen, QColor, QBrush
from PyQt5.QtWidgets import QApplication, QGraphicsItem, QMainWindow, QGraphicsScene, QGraphicsView, \
QGraphicsEllipseItem, QUndoStack, QUndoCommand
import random
class CustomUndoRedoStack(QUndoStack):
instance = None
def __init__(self):
if not CustomUndoRedoStack.instance:
CustomUndoRedoStack.instance = self
super(CustomUndoRedoStack, self).__init__()
#staticmethod
def get_instance():
return CustomUndoRedoStack.instance
class MovingMultiItemsCommand(QUndoCommand):
def __init__(self, new_items_pos: Dict[QGraphicsItem], old_items_pos: Dict[QGraphicsItem]):
super(MovingMultiItemsCommand, self).__init__()
self.new_items_pos = new_items_pos
self.old_items_pos = old_items_pos
CustomUndoRedoStack.get_instance().push(self)
def undo(self) -> None:
for item in self.old_items_pos:
item.setPos(self.old_items_pos[item])
super(MovingMultiItemsCommand, self).undo()
def redo(self) -> None:
for item in self.new_items_pos:
item.setPos(self.new_items_pos[item])
super(MovingMultiItemsCommand, self).redo()
class CustomQGraphicsEllipseItem(QGraphicsEllipseItem):
def __init__(self, x, y):
super(CustomQGraphicsEllipseItem, self).__init__(x, y, 20, 20)
self.setFlag(QGraphicsItem.ItemIsSelectable)
self.setFlag(QGraphicsItem.ItemIsMovable)
self.setPen(QPen(QColor(255, 128, 0), 0.5, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin))
self.setBrush(QBrush(QColor(255, 128, 20, 128)))
class MyGraphicsView(QGraphicsView):
def __init__(self):
super(MyGraphicsView, self).__init__()
self.setDragMode(QGraphicsView.RubberBandDrag)
self._isPanning = False
self._mousePressed = False
self.setCacheMode(QGraphicsView.CacheBackground)
self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
class MyGraphicsScene(QGraphicsScene):
def __init__(self):
super(MyGraphicsScene, self).__init__()
self.setBackgroundBrush(QBrush(QColor(50, 50, 50)))
self.old_items_pos = {}
self.new_items_pos = {}
# ------- I want something like the following -----------------------------
def selected_items_before_change(self):
for item in self.selectedItems():
self.old_items_pos[item] = item.pos()
def selected_items_after_change(self):
for item in self.selectedItems():
self.new_items_pos[item] = item.pos()
def selected_item_position_changed(self):
"""
This method must be triggered only and only once after selected items position has been changed (NOT WHILE)
"""
MovingMultiItemsCommand(self.new_items_pos, self.old_items_pos)
# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
class MyMainWindow(QMainWindow):
def __init__(self):
super(MyMainWindow, self).__init__()
self.setWindowTitle("Test")
self.resize(800, 600)
self.gv = MyGraphicsView()
self.gv.setScene(MyGraphicsScene())
self.setCentralWidget(self.gv)
self.populate()
def populate(self):
scene = self.gv.scene()
for i in range(500):
x = random.randint(0, 1000)
y = random.randint(0, 1000)
rect = CustomQGraphicsEllipseItem(x, y)
scene.addItem(rect)
def main():
app = QApplication(sys.argv)
ex = MyMainWindow()
ex.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
C++ answers will be good as well, but Python is preferable :)
The mouse movement of selectable items is handled by the graphics scene, starting with its mousePressEvent() and ending with the corresponding mouseReleaseEvent().
This means that you can create a QUndoCommand based on the selected items (if any) after the default implementation of mouse button press/release is called. This will be valid for any movement, including when just one item has been moved.
class ItemMovedUndoCommand(QUndoCommand):
def __init__(self, oldPositions, newPositions):
if len(oldPositions) == 1:
pos = oldPositions.values()[0]
text = 'Item moved to {}x{}'.format(
pos.x(), pos.y())
else:
text = '{} items moved'.format(len(oldPositions))
super().__init__(text)
self.oldPositions = oldPositions
self.newPositions = newPositions
def redo(self):
for item, pos in self.newPositions.items():
item.setPos(pos)
def undo(self):
for item, pos in self.oldPositions.items():
item.setPos(pos)
class CustomQGraphicsEllipseItem(QGraphicsEllipseItem):
def __init__(self, x, y):
super(CustomQGraphicsEllipseItem, self).__init__(-10, -10, 20, 20)
self.setPos(x, y)
self.setFlag(QGraphicsItem.ItemIsSelectable)
self.setFlag(QGraphicsItem.ItemIsMovable)
self.setPen(QPen(QColor(255, 128, 0),
0.5, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin))
self.setBrush(QBrush(QColor(255, 128, 20, 128)))
class MyGraphicsView(QGraphicsView):
def __init__(self):
super(MyGraphicsView, self).__init__()
self.setDragMode(QGraphicsView.RubberBandDrag)
self._isPanning = False
self._mousePressed = False
self.setCacheMode(QGraphicsView.CacheBackground)
self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
class MyGraphicsScene(QGraphicsScene):
itemsMoved = pyqtSignal(object, object)
def __init__(self):
super(MyGraphicsScene, self).__init__()
self.setBackgroundBrush(QBrush(QColor(50, 50, 50)))
self.oldPositions = {}
def mousePressEvent(self, event):
super().mousePressEvent(event)
if event.button() == Qt.LeftButton:
self.oldPositions = {i:i.pos() for i in self.selectedItems()}
def mouseReleaseEvent(self, event):
super().mouseReleaseEvent(event)
if event.button() == Qt.LeftButton and self.oldPositions:
self.itemsMoved.emit(self.oldPositions,
{i:i.pos() for i in self.oldPositions.keys()})
self.oldPositions = {}
class MyMainWindow(QMainWindow):
def __init__(self):
super(MyMainWindow, self).__init__()
self.setWindowTitle("Test")
self.resize(800, 600)
self.gv = MyGraphicsView()
self.scene = MyGraphicsScene()
self.gv.setScene(self.scene)
self.setCentralWidget(self.gv)
toolBar = QToolBar()
self.addToolBar(Qt.TopToolBarArea, toolBar)
self.undoStack = QUndoStack()
toolBar.addAction(self.undoStack.createUndoAction(self.scene))
toolBar.addAction(self.undoStack.createRedoAction(self.scene))
self.populate()
self.scene.itemsMoved.connect(self.itemsMoved)
def itemsMoved(self, oldPositions, newPositions):
self.undoStack.push(ItemMovedUndoCommand(oldPositions, newPositions))
def populate(self):
scene = self.gv.scene()
for i in range(500):
x = random.randint(0, 1000)
y = random.randint(0, 1000)
rect = CustomQGraphicsEllipseItem(x, y)
scene.addItem(rect)

'QWidget' object has no attribute 'set_status_message'

I use PyQt5 and Python2.7.
I have four Classes. App, UIWidget, PlayStreaming and Thread.
App is parent of UIWidget.
UIWidget is parent of PlayStreaming.
PlayStreaming is parent of Thread.
I like to pass Statusbar message from Thread Class to App Class, so that I can update status.
I use self.parent().set_status_message('') from children classes subsequently to display message with self.statusBar().showMessage('') in App class.
But I have error in UIWidget as
AttributeError: 'QWidget' object has no attribute 'set_status_message'
Aborted (core dumped)
How can I update to Status bar in MainWindow from Child class?
My code is as follow.
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import QApplication, QMainWindow
import cv2
import time
import face_recognition.api as face_recognition
class Thread(QtCore.QThread):
changePixmap = QtCore.pyqtSignal(QtGui.QImage)
scaled_size = QtCore.QSize(640, 480)
curScale=1.0
def run(self):
cap = cv2.VideoCapture(-1)
cap.set(3,1280);
cap.set(4,1024);
time.sleep(2)
self.maxHeight=cap.get(cv2.CAP_PROP_FRAME_HEIGHT)
self.maxScale=self.maxHeight/480.0
while True:
ret, frame = cap.read()
if ret:
r=1
face_locations=[]
rescaleSize=int(480*self.curScale)
if(frame.shape[0] > 480 and frame.shape[1] > 640):
r = rescaleSize / float(frame.shape[0])
dim = (int(frame.shape[1] * r), rescaleSize)
face_locations = face_recognition.face_locations(cv2.resize(frame, dim, fx=0.0, fy=0.0))
else:
face_locations = face_recognition.face_locations(frame)
for face_location in face_locations:
top, right, bottom, left = face_location
cv2.rectangle(frame,(int(right/r),int(top/r)),(int(left/r),int(bottom/r)),(0,255,0),2)
rgbImage = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
convertToQtFormat = QtGui.QImage(rgbImage.data, rgbImage.shape[1], rgbImage.shape[0], QtGui.QImage.Format_RGB888)
p = convertToQtFormat.scaled(self.scaled_size, QtCore.Qt.KeepAspectRatio)
self.changePixmap.emit(p)
#QtCore.pyqtSlot(QtCore.QSize)
def scaled(self, scaled_size):
self.scaled_size = scaled_size
#QtCore.pyqtSlot()
def scaleup(self):
self.curScale = self.curScale + 0.1
if self.curScale > self.maxScale:
self.curScale = self.maxScale
self.parent().set_status_message('Cur scale:'+str(self.curScale))
#QtCore.pyqtSlot()
def scaledown(self):
self.curScale = self.curScale - 0.1
if self.curScale < 1.0:
self.curScale = 1.0
self.parent().set_status_message('Cur scale:'+str(self.curScale))
class PlayStreaming(QtWidgets.QLabel):
reSize = QtCore.pyqtSignal(QtCore.QSize)
scaleupSignal = QtCore.pyqtSignal()
scaledownSignal = QtCore.pyqtSignal()
def __init__(self):
super(PlayStreaming, self).__init__()
self.initUI()
#QtCore.pyqtSlot(QtGui.QImage)
def setImage(self, image):
self.label.setPixmap(QtGui.QPixmap.fromImage(image))
def initUI(self):
self.setWindowTitle("Image")
# create a label
self.label = QtWidgets.QLabel(self)
th = Thread(self)
th.changePixmap.connect(self.setImage)
self.scaleupSignal.connect(th.scaleup)
self.scaledownSignal.connect(th.scaledown)
self.reSize.connect(th.scaled)
th.start()
lay = QtWidgets.QVBoxLayout(self)
lay.addWidget(self.label, alignment=QtCore.Qt.AlignCenter)
def resizeEvent(self, event):
self.reSize.emit(self.size())
def set_status_message(self, message):
return self.parent().set_status_message(message)
class UIWidget(QtWidgets.QWidget):
def __init__(self, parent=None):
super(UIWidget, self).__init__(parent)
# Initialize tab screen
self.tabs = QtWidgets.QTabWidget()
self.tab1 = QtWidgets.QWidget()
self.tab2 = QtWidgets.QWidget()
self.tab3 = QtWidgets.QWidget()
# Add tabs
self.tabs.addTab(self.tab1, "Face")
self.tabs.addTab(self.tab2, "Human")
self.tabs.addTab(self.tab3, "Vehicle")
self.display = PlayStreaming()
# Create first tab
self.createGridLayout()
self.tab1.layout = QtWidgets.QVBoxLayout()
self.tab1.layout.addWidget(self.display, stretch=1)
self.tab1.layout.addWidget(self.horizontalGroupBox)
self.tab1.setLayout(self.tab1.layout)
# Add tabs to widget
layout = QtWidgets.QVBoxLayout(self)
layout.addWidget(self.tabs)
def createGridLayout(self):
self.horizontalGroupBox = QtWidgets.QGroupBox("")
self.horizontalGroupBox.setStyleSheet("QGroupBox{ background-color: red; border: none;}")
hlay1 = QtWidgets.QHBoxLayout()
self.TestButton=QtWidgets.QPushButton('Test')
hlay1.addWidget(self.TestButton)
self.RunButton=QtWidgets.QPushButton('Run')
hlay1.addWidget(self.RunButton)
self.ScaleUpButton=QtWidgets.QPushButton('ScaleUp')
self.ScaleUpButton.clicked.connect(self.display.scaleupSignal)
hlay1.addWidget(self.ScaleUpButton)
self.ScaleDownButton=QtWidgets.QPushButton('ScaleDown')
self.ScaleDownButton.clicked.connect(self.display.scaledownSignal)
hlay1.addWidget(self.ScaleDownButton)
hlay2 = QtWidgets.QHBoxLayout()
hlay2.addWidget(QtWidgets.QPushButton('Set Faces'))
hlay2.addWidget(QtWidgets.QPushButton('FacePose'))
hlay2.addWidget(QtWidgets.QPushButton('Gender'))
hlay2.addWidget(QtWidgets.QPushButton('Age'))
hlay2.addWidget(QtWidgets.QPushButton('Recognize'))
layout = QtWidgets.QVBoxLayout()
layout.addLayout(hlay1)
layout.addLayout(hlay2)
self.horizontalGroupBox.setLayout(layout)
def set_status_message(self, message):
return self.statusBar().set_status_message(message)
class App(QMainWindow):
def __init__(self):
super(App,self).__init__()
self.title = 'FaceHumanVehicle'
self.left = 10
self.top = 10
self.width = 1000
self.height = 800
self.initUI()
def initUI(self):
self.setWindowTitle(self.title)
self.setGeometry(self.left, self.top, self.width, self.height)
self.form_widget = UIWidget(self)
self.statusBar().showMessage('')
self.setCentralWidget(self.form_widget)
self.show()
def set_status_message(self, message):
return self.statusBar().showMessage(message)
if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
ex = App()
sys.exit(app.exec_())
Whenever you add a widget to a layout, it will be automatically re-parented to the widget that contains the layout. So this code:
self.display = PlayStreaming()
# Create first tab
self.createGridLayout()
self.tab1.layout = QtWidgets.QVBoxLayout()
self.tab1.layout.addWidget(self.display, stretch=1)
will mean that self.display.parent() returns self.tab1, which obviously does not have a set_status_message method (since it's just a plain QWidget).
However, it's bad practice to try to directly access gui methods from a thread, so a better solution is to emit a custom signal that sends the status-bar message:
class Thread(QtCore.QThread):
statusMessage = QtCore.pyqtSignal(str)
...
def scaleup(self):
...
self.statusMessage.emit('Cur scale:'+str(self.curScale))
You can then connect this up within your PlayStreaming class and use its window() method to access the top-level main-window:
class PlayStreaming(QtWidgets.QLabel):
...
def initUI(self):
...
th = Thread(self)
th.statusMessage.connect(self.handle_status_message)
def handle_status_message(self, message):
self.window().set_status_message(message)

Modify inbuilt WxPython widget

How to modify the combobox in wxPython to dropdown a checklistbox so I can select the choices?
something like above. I know that ComboBox class is available and I need to inherit it add the feature of checkbox to dropdown list. But I am not getting the proper way to start with it.
Take a look at the ComboCtrl class. It allows you to provide the window that implements the combo's drop-down. There are some examples in the wxPython demo.
I haven't had the time to grind through ComboCtrl and it looks daunting.
However, an approximation of what you want can be achieved by torturing a wx.Dialog.
import wx
import wx.lib.scrolledpanel as scrolled
class MyFrame(wx.Frame):
def __init__(self, parent):
wx.Frame.__init__(self, parent, -1, "CheckBox Dialog",size=(400,250))
self.panel = wx.Panel(self)
sizer = wx.BoxSizer(wx.VERTICAL)
self.log = wx.TextCtrl(self.panel, wx.ID_ANY, size=(350,150),style = wx.TE_MULTILINE|wx.TE_READONLY|wx.VSCROLL)
self.button = wx.Button(self.panel, label="Choose Colours")
sizer.Add(self.log, 0, wx.EXPAND | wx.ALL, 10)
sizer.Add(self.button, 0, wx.EXPAND | wx.ALL, 10)
self.panel.SetSizer(sizer)
self.Bind(wx.EVT_BUTTON, self.OnButton)
self.panel.options = ['Red','Green','Black','White','Orange','Blue','Yellow']
self.panel.selected = [0,0,0,0,0,0,0]
def OnButton(self,event):
dlg = ShowOptions(parent = self.panel)
dlg.ShowModal()
if dlg.result:
result_text = 'Selected: '
for item in range(len(dlg.result)):
if dlg.result[item]:
result_text += self.panel.options[item]+' '
self.log.AppendText(result_text+'\n\n')
self.panel.selected = dlg.result
else:
self.log.AppendText("No selection made\n\n")
dlg.Destroy()
class ShowOptions(wx.Dialog):
def __init__(self, parent):
self.options = parent.options
self.selected = parent.selected
o_str = ''
for item in self.options:
o_str = o_str+item+','
wx.Dialog.__init__(self, parent, wx.ID_ANY, "CheckBoxes", size= (400,250))
self.top_panel = wx.Panel(self,wx.ID_ANY)
self.avail_options = wx.TextCtrl(self.top_panel, wx.ID_ANY, o_str,style = wx.TE_READONLY)
self.bot_panel = wx.Panel(self,wx.ID_ANY)
self.scr_panel = scrolled.ScrolledPanel(self,wx.ID_ANY)
top_sizer = wx.BoxSizer(wx.VERTICAL)
scr_sizer = wx.BoxSizer(wx.VERTICAL)
bot_sizer = wx.BoxSizer(wx.VERTICAL)
self.items = []
for item in range(len(self.options)):
self.item = wx.CheckBox(self.scr_panel,-1,self.options[item])
self.item.SetValue(self.selected[item])
self.items.append(self.item)
self.item.Bind(wx.EVT_CHECKBOX, self.Select)
self.saveButton =wx.Button(self.bot_panel, label="Save")
self.closeButton =wx.Button(self.bot_panel, label="Cancel")
self.saveButton.Bind(wx.EVT_BUTTON, self.SaveOpt)
self.closeButton.Bind(wx.EVT_BUTTON, self.OnQuit)
self.Bind(wx.EVT_CLOSE, self.OnQuit)
top_sizer.Add(self.avail_options,0,flag=wx.EXPAND)
for item in self.items:
scr_sizer.Add(item,0)
bot_sizer.Add(self.saveButton,0,flag=wx.CENTER)
bot_sizer.Add(self.closeButton,0,flag=wx.CENTER)
self.scr_panel.SetupScrolling()
self.top_panel.SetSizer(top_sizer)
self.scr_panel.SetSizer(scr_sizer)
self.bot_panel.SetSizer(bot_sizer)
mainsizer = wx.BoxSizer(wx.VERTICAL)
mainsizer.Add(self.top_panel,0,flag=wx.EXPAND)
mainsizer.Add(self.scr_panel,1,flag=wx.EXPAND)
mainsizer.Add(self.bot_panel,0,flag=wx.EXPAND)
self.SetSizer(mainsizer)
self.Select(None)
self.Show()
def Select(self, event):
selection = []
for item in self.items:
x = item.GetValue()
selection.append(x)
selected_text = ''
for item in range(len(selection)):
if selection[item]:
selected_text += self.options[item]+' '
self.avail_options.SetValue(selected_text)
def OnQuit(self, event):
self.result = None
self.Destroy()
def SaveOpt(self, event):
self.result = []
for item in self.items:
x = item.GetValue()
self.result.append(x)
self.Destroy()
app = wx.App()
frame = MyFrame(None)
frame.Show()
app.MainLoop()
I created a widget using wx.ComboCtrl, as suggested by Robin Dunn.
Feel free to use it, or modify it any way you like.
You can also find a more advanced version of it on my GitHub account.
import wx
import wx.lib.mixins.listctrl
import operator
import functools
import contextlib
#contextlib.contextmanager
def asCM(function, *args, **kwargs):
"""Used to build with wxWidgets as context managers to help organize code."""
yield function(*args, **kwargs)
class CheckListCtrl(wx.ComboCtrl):
"""A wxListCtrl-like widget where each item in the drop-down list has a check box.
Modified code from: https://github.com/wxWidgets/Phoenix/blob/master/demo/ComboCtrl.py
"""
def __init__(self, parent, myId = None, initial = None, position = None, size = None, readOnly = False, **kwargs):
"""
parent (wxWindow) – Parent window (must not be None)
initial (str) – Initial selection string
readOnly (bool) - Determiens if the user can modify values in this widget
Example Input: CheckListCtrl(self)
"""
self.parent = parent
#Configure settings
style = []
if (readOnly):
style.append(wx.CB_READONLY)
#Create object
super().__init__(parent,
id = myId or wx.ID_ANY,
value = initial or "",
pos = position or wx.DefaultPosition,
size = size or wx.DefaultSize,
style = functools.reduce(operator.ior, style or (0,)))
self.popup = self.MyPopup(self, **kwargs)
def Append(self, *args, **kwargs):
self.popup.Append(*args, **kwargs)
class MyPopup(wx.ComboPopup):
"""The popup control used by CheckListCtrl."""
def __init__(self, parent, *, popupId = None, multiple = True, prefHeight = None,
image_check = None, image_uncheck = None, lazyLoad = False):
"""
multiple (bool) - Determines if the user can check multiple boxes or not
lazyLoad (bool) - Determines if when Create() is called
- If True: Waits for the first time the popup is called
- If False: Calls it during the build process
prefHeight (int) - What height you would prefer the popup box use
- If None: Will calculate what hight to use based on it's contents
- If -1: Will use the default height
"""
self.parent = parent
self.prefHeight = prefHeight
self._buildVar_myId = popupId
self._buildVar_multiple = multiple
self._buildVar_lazyLoad = lazyLoad
self._buildVar_image_check = image_check
self._buildVar_image_uncheck = image_uncheck
super().__init__()
parent.SetPopupControl(self)
def Create(self, parent):
self.checkList = self.MyListCtrl(self, parent,
myId = self._buildVar_myId,
multiple = self._buildVar_multiple,
image_check = self._buildVar_image_check,
image_uncheck = self._buildVar_image_uncheck)
return True
def Append(self, *args, **kwargs):
self.checkList.Append(*args, **kwargs)
def GetControl(self):
return self.checkList
def GetAdjustedSize(self, minWidth, prefHeight, maxHeight):
if (self.prefHeight is -1):
return super().GetAdjustedSize(minWidth, prefHeight, maxHeight)
elif (self.prefHeight is not None):
return (minWidth, min(self.prefHeight, maxHeight))
return self.checkList.GetBestSize(minWidth, prefHeight, maxHeight)
def LazyCreate(self):
return self._buildVar_lazyLoad
class MyListCtrl(wx.ListCtrl, wx.lib.mixins.listctrl.CheckListCtrlMixin):
"""Modified code from: https://github.com/wxWidgets/wxPython/blob/master/demo/CheckListCtrlMixin.py"""
def __init__(self, parent, root, *, myId = None, multiple = False, image_check = None, image_uncheck = None):
"""
multiple (bool) - Determines if the user can check multiple boxes or not
"""
self.parent = parent
#Configure settings
style = [wx.LC_LIST, wx.SIMPLE_BORDER]
if (not multiple):
style.append(wx.LC_SINGLE_SEL)
#Create object
wx.ListCtrl.__init__(self, root, id = myId or wx.ID_ANY, style = functools.reduce(operator.ior, style or (0,)))
wx.lib.mixins.listctrl.CheckListCtrlMixin.__init__(self, check_image = image_check, uncheck_image = image_uncheck)
def Append(self, value, default = False):
"""Appends the given item to the list.
value (str) - What the item will say
default (bool) - What state the check box will start out at
Example Input: Append("lorem")
Example Input: Append("lorem", default = True)
"""
n = self.GetItemCount()
self.InsertItem(n, value)
if (default):
self.CheckItem(n)
def GetBestSize(self, minWidth, prefHeight, maxHeight):
return (minWidth, min(prefHeight, maxHeight, sum(self.GetItemRect(i)[3] for i in range(self.GetItemCount())) + self.GetItemRect(0)[3]))
# this is called by the base class when an item is checked/unchecked
def OnCheckItem(self, index, state):
print(index, state)
if (__name__ == "__main__"):
class TestFrame(wx.Frame):
def __init__(self):
super().__init__(None, wx.ID_ANY, "Lorem Ipsum")
with asCM(wx.Panel, self, wx.ID_ANY) as myPanel:
with asCM(wx.BoxSizer, wx.VERTICAL) as mySizer:
with asCM(CheckListCtrl, myPanel, prefHeight = None) as myWidget:
myWidget.Append("lorem")
myWidget.Append("ipsum", default = True)
myWidget.Append("dolor")
mySizer.Add(myWidget, 0, wx.ALL, 5)
myPanel.SetSizer(mySizer)
####################################
app = wx.App(False)
frame = TestFrame()
frame.Show()
app.MainLoop()

Signal connections in a separate class

I have some problems with refactoring of my code. Here is my small example:
def __init__(self):
super(Example, self).__init__()
self.initUI()
def initUI(self):
but1 = QtGui.QPushButton("OK1")
myUtils = ButtinUtils()
but2 = myUtils.createButton(self.sender())
hbox = QtGui.QFormLayout()
hbox.addWidget(but1)
hbox.addWidget(but2)
self.setLayout(hbox)
self.setGeometry(300, 300, 300, 150)
self.setWindowTitle('Buttons')
self.show()
but1.clicked.connect(self.foo1)
def foo1(self):
print "foo1 called"
def main():
app = QtGui.QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
The ideas is to create my second button in a own class. I can display the button on my main window, but how can I get a connection?
Here is the second class:
class ButtinUtils(object):
def __init__(self):
self.createButton()
#b1 = QtGui.QPushButton("OK")
def createButton(self):
but2 = QtGui.QPushButton("OK2")
return but2
It would be great to outsource the event handler also to this util class.
Any ideas?

Add plus button to TabWidget pyqt4

The following code gives a tab interface which can dynamically add tabs
import sys, random
from PyQt4 import QtCore, QtGui
class TabContainer(QtGui.QWidget):
def __init__(self):
super(TabContainer, self).__init__()
self.next_item_is_table = False
self.initUI()
def initUI(self):
self.setGeometry( 150, 150, 650, 350)
self.tabwidget = QtGui.QTabWidget(self)
vbox = QtGui.QVBoxLayout()
vbox.addWidget(self.tabwidget)
self.setLayout(vbox)
self.pages = []
self.add_page()
self.show()
def create_page(self, *contents):
page = QtGui.QWidget()
vbox = QtGui.QVBoxLayout()
for c in contents:
vbox.addWidget(c)
page.setLayout(vbox)
return page
def create_table(self):
rows, columns = random.randint(2,5), random.randint(1,5)
table = QtGui.QTableWidget( rows, columns )
for r in xrange(rows):
for c in xrange(columns):
table.setItem( r, c, QtGui.QTableWidgetItem( str( random.randint(0,10) ) ) )
return table
def create_list(self):
list = QtGui.QListWidget()
columns = random.randint(2,5)
for c in xrange(columns):
QtGui.QListWidgetItem( str( random.randint(0,10) ), list )
return list
def create_new_page_button(self):
btn = QtGui.QPushButton('Create a new page!')
btn.clicked.connect(self.add_page)
return btn
def add_page(self):
if self.next_item_is_table:
self.pages.append( self.create_page( self.create_table(), self.create_new_page_button() ) )
self.next_item_is_table = False
else:
self.pages.append( self.create_page( self.create_list(), self.create_new_page_button() ) )
self.next_item_is_table = True
self.tabwidget.addTab( self.pages[-1] , 'Page %s' % len(self.pages) )
self.tabwidget.setCurrentIndex( len(self.pages)-1 )
app = QtGui.QApplication(sys.argv)
ex = TabContainer()
sys.exit(app.exec_())
But I want to add a new tab button next to the tab bar similar to any browser...
I searched for it but I wasn't able to find any way to add a plus button...Is there any property in the TabWidget or do I need to add a new button over there..?
The source for the above code is : Dynamically change view of tabs in a QTabWidget (PyQt)
You could set a corner-widget on the tab-bar:
self.tabButton = QtGui.QToolButton(self)
self.tabButton.setText('+')
font = self.tabButton.font()
font.setBold(True)
self.tabButton.setFont(font)
self.tabwidget.setCornerWidget(self.tabButton)
self.tabButton.clicked.connect(self.add_page)