PyQt5 - How can I add image in 'pushbutton' widget? | (not icon) - image

Is there a function or option that adds an image in PushButton widget? In this situation, The added image means an image as a background applied to the entire widget, not an image as an 'icon'. I tried to find this option and I use the 'setStyleSheet' function, but it doesn't work. What is a problem, and how can I add an image in pushbutton?
btn6.setStyleSheet(
"color: black;"
"border-style: solid;"
"border-width: 2px;"
"border-color: #FFB400;"
"border-radius: 3px;"
"background-color: #FFD732;"
"**background-image: url('D:\PyQt5_Tutorial\Test.png')")**

You can just override QPushButton.paintEvent() for this. And dont forget to add interactivity to reflect different states of button: sunken, disabled, mouse hover, input focus.
from PyQt5 import QtWidgets, QtGui
class Button(QtWidgets.QPushButton):
def __init__(self, parent = None) -> None:
super().__init__(parent)
self._image = None
def setImage(self, image):
self._image = image
self.update()
class Button(QtWidgets.QPushButton):
def __init__(self, parent = None) -> None:
super().__init__(parent)
self._image = None
def setImage(self, image):
self._image = image
self.update()
def paintEvent(self, event):
if self._image is None:
return
opt = QtWidgets.QStyleOptionButton()
self.initStyleOption(opt)
rect = self.rect()
painter = QtGui.QPainter(self)
self.style().drawControl(QtWidgets.QStyle.CE_PushButtonBevel, opt, painter, self)
if opt.state & QtWidgets.QStyle.State_Sunken:
rect.adjust(2,2,2,2)
painter.drawImage(rect, self._image)
if opt.state & QtWidgets.QStyle.State_MouseOver:
color = self.palette().color(QtGui.QPalette.Highlight)
color.setAlpha(50)
painter.fillRect(self.rect(), color)
if __name__ == "__main__":
app = QtWidgets.QApplication([])
button = Button()
button.setImage(QtGui.QImage("D:\\PyQt5_Tutorial\\Test.png"))
button.show()
app.exec()

Related

wxPython - PlateButton stopping wx.EVT_KEY_DOWN event

In my app, when I press that PlateButton, the wx.EVT_KEY_DOWN stop working. I don't know what's going on. If I erase the bmpImage code and set the parent of the PlateButton to self, the event doesn't even fire in the first place.
Thanks!
import wx
import wx.lib.platebtn as pb
class MainFrame(wx.Frame):
def __init__(self, parent):
super().__init__(parent)
self.initUI()
self.Bind(wx.EVT_KEY_DOWN, self.OnKey)
def initUI(self):
bmpImage = wx.StaticBitmap(self, wx.ID_ANY)
bmpImage.SetBitmap(wx.Bitmap('image.JPG', wx.BITMAP_TYPE_ANY))
btn = pb.PlateButton(bmpImage, -1, 'Click Me!', style=pb.PB_STYLE_NOBG)
def OnKey(self, event):
print('Key pressed!')
event.Skip()
app = wx.App()
frame = MainFrame(None)
frame.Show()
app.MainLoop()
If you run the following code, you'll see that the platebutton is grabbing the event and obviously not skipping the event, thus it is not available to the frame, which you are binding to.
import wx
import wx.lib.platebtn as pb
class MainFrame(wx.Frame):
def __init__(self, parent):
super().__init__(parent)
self.initUI()
self.Bind(wx.EVT_KEY_DOWN, self.OnKey)
def initUI(self):
text = wx.StaticText(self, -1, "Key Test", pos=(10, 10))
btn = pb.PlateButton(self, -1, 'Click Me!', pos=(10,40), size=(100,25))
btn.Bind(wx.EVT_KEY_DOWN, self.OnKey)
def OnKey(self, event):
print(event.GetEventObject())
print('Key pressed!')
event.Skip()
app = wx.App()
frame = MainFrame(None)
frame.Show()
app.MainLoop()

PySide2, How to create a Widget above Docking

The docking is created as required. What I'm not able to do is creating 'Shelf' widget above docking.
It shouldn't be part of docking and it should remain at the top. When hidden, docks should cover up the
space and when shown again docks should move below.
import sys
from PySide2 import QtGui, QtCore, QtWidgets
class Shelf(QtWidgets.QTabWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.tab1 = QtWidgets.QWidget()
self.tab2 = QtWidgets.QWidget()
self.tab3 = QtWidgets.QWidget()
self.addTab(self.tab1, "Tab 1")
self.addTab(self.tab2, "Tab 2")
self.addTab(self.tab3, "Tab 3")
class MainWindow(QtWidgets.QMainWindow):
def __init__(self):
super(MainWindow, self).__init__()
self.centre = QtWidgets.QMainWindow(self)
self.centre.setWindowFlags(QtCore.Qt.Widget)
self.centre.setDockOptions(
QtWidgets.QMainWindow.AnimatedDocks |
QtWidgets.QMainWindow.AllowNestedDocks)
self.setCentralWidget(self.centre)
self.dockCentre1 = QtWidgets.QDockWidget(self.centre)
self.dockCentre1.setWindowTitle('Centre 1')
self.centre.addDockWidget(QtCore.Qt.LeftDockWidgetArea, self.dockCentre1)
self.dockCentre2 = QtWidgets.QDockWidget(self.centre)
self.dockCentre2.setWindowTitle('Centre 2')
self.centre.addDockWidget(QtCore.Qt.LeftDockWidgetArea, self.dockCentre2)
self.dockLeft = QtWidgets.QDockWidget(self)
self.dockLeft.setWindowTitle('Left')
self.addDockWidget(QtCore.Qt.LeftDockWidgetArea, self.dockLeft)
self.dockLeft1 = QtWidgets.QDockWidget(self)
self.dockLeft1.setWindowTitle('Left')
self.addDockWidget(QtCore.Qt.LeftDockWidgetArea, self.dockLeft1)
self.dockRight = QtWidgets.QDockWidget(self)
self.dockRight.setWindowTitle('Right')
self.addDockWidget(QtCore.Qt.RightDockWidgetArea, self.dockRight)
self.dockRight1 = QtWidgets.QDockWidget(self)
self.dockRight1.setWindowTitle('Right')
self.addDockWidget(QtCore.Qt.RightDockWidgetArea, self.dockRight1)
self.menuBar().addMenu('File').addAction('Quit', self.close)
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
window = MainWindow()
window.setGeometry(500, 50, 600, 400)
window.show()
sys.exit(app.exec_())

PySide PyQt QDataWidgetMapper

I try to connect a QtGui.QPlainTextEdit to a Model with QDataWidgetMapper.
I dont get any errors, just nothing in the TextEdit.
I dont get it and i cant find good example Code.
Here is some ExampleCode.
I really hope that someone could help me.
from PySide import QtCore, QtGui
import sys
class ComponentsListModel(QtCore.QAbstractListModel):
def __init__(self, components=[], parent = None):
super(ComponentsListModel, self).__init__(parent=None)
self.components = components
self.list = parent
def rowCount(self, parent):
return len(self.components)
def data(self, index, role):
row = index.row()
if role == QtCore.Qt.DisplayRole:#index.isValid() and
value = self.components[row]
return value
class MainWindow(QtGui.QWidget):
def __init__(self):
super(MainWindow, self).__init__()
self._build_ui()
def _build_ui(self):
self.layout = QtGui.QVBoxLayout()
self.listView = QtGui.QListView()
self.model = ComponentsListModel(components = ['1', '2', '3'])
self.listView.setModel(self.model)
self.text = QtGui.QPlainTextEdit()
self.layout.addWidget(self.listView)
self.layout.addWidget(self.text)
self.setLayout(self.layout)
self._mapper = QtGui.QDataWidgetMapper(self)
self._mapper.setModel(self.model)
self._mapper.setSubmitPolicy(QtGui.QDataWidgetMapper.AutoSubmit)
self._mapper.addMapping(self.text, 0)
self._mapper.toFirst()
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
app.setStyle('Plastique')
mySW = MainWindow()
mySW.show()
sys.exit(app.exec_())
You will need to add a condition for Qt.EditRole in your data function inside ComponentsListModel class
if role == Qt.EditRole:
value = self.components[row]
return value

PyQt Get the result from a popup window

I want to open a popup window in pyqt interface using this class
class MyPopup(QWidget):
def __init__(self):
QWidget.__init__(self)
self.initUI()
self.res=0
def initUI(self):
self.btn = QtGui.QPushButton('Continue', self)
self.btn.move(20, 160)
self.btn.clicked.connect(self.showDialogcontinue)
self.btn = QtGui.QPushButton('Quit', self)
self.btn.move(180,160)
self.btn.clicked.connect(self.showDialogstop)
self.setGeometry(600, 600, 290, 150)
self.setWindowTitle('EUT Setup')
self.show()
def showDialogcontinue(self):
self.close()
self.res=1
def showDialogstop(self):
self.close()
self.res=0
So when I use it, in a push button method
self.w = MyPopup()
self.w.setGeometry(QRect(100, 100, 400, 200))
self.w.show()
if self.w.res==1:
print "start"
self.__thread.start()
else:
print "stop"
I can't get the result to launch or not mythread ___thread .
Please what's wrong? Could you help?
The problem is that showing a widget does not block the execution of code. So the if check is reached long before any button in the widget is clicked.
To solve this you can change the parent class to a QDialog, and show it with exec_() which will block until the dialog is closed.
And setting self.res=0 before self.initUI() since anything after self.initUI() would be called after the dialog closed. And that would reset res to 0 again.
class MyPopup(QtGui.QDialog):
def __init__(self, parent=None):
super(MyPopup, self).__init__(parent)
self.res=0
self.initUI()
def initUI(self):
self.btn = QtGui.QPushButton('Continue', self)
self.btn.move(20, 160)
self.btn.clicked.connect(self.showDialogcontinue)
self.btn = QtGui.QPushButton('Quit', self)
self.btn.move(180,160)
self.btn.clicked.connect(self.showDialogstop)
self.setGeometry(600, 600, 290, 150)
self.setWindowTitle('EUT Setup')
self.exec_()
def showDialogcontinue(self):
self.res=1
self.close()
def showDialogstop(self):
self.res=0
self.close()
if all you need is a single true\false value back from the dialog. You can do it easier using the accept\reject functions of a QDialog.
class MyPopup(QtGui.QDialog):
def __init__(self):
super(MyPopup, self).__init__()
self.initUI()
def initUI(self):
self.btn = QtGui.QPushButton('Continue', self)
self.btn.move(20, 160)
self.btn.clicked.connect(self.accept)
self.btn = QtGui.QPushButton('Quit', self)
self.btn.move(180,160)
self.btn.clicked.connect(self.reject)
self.setGeometry(600, 600, 290, 150)
self.setWindowTitle('EUT Setup')
w = MyPopup()
if w.exec_():
print("Start thread")
else:
print("Stop")

Is possible to put an image instead of a button, and make it clickable?

Is possible to put an Image into a GUI Application and make it clickable?
I used to make a button like this:
img = QPixmap(15, 15)
img.fill(Qt.grey)
button = QPushButton(QIcon(img))
button.clicked.connect(self.button_click)
Link http://imagizer.imageshack.us/v2/800x600q90/834/kaqc.png
But I'd prefer to use an image, instead of having a button with an icon..
I had the same requirement and solved it by subclassing QLabel, as yshurik suggests. The amount of additional code is very limited. Here is a working implementation:
class CClickableLabel : public QLabel
{
Q_OBJECT
public:
CClickableLabel(QString text, QWidget *parent = 0) : QLabel(text, parent) {}
~CClickableLabel() {}
signals:
void clicked();
protected:
void mousePressEvent(QMouseEvent *event) { emit clicked(); }
};
Create a instance CClickableLabel, use setPixmap() to set the image and listen to the clicked() signal. That should do the trick.
Here's simple demo script that shows how to make a grid of clickable labels:
from random import shuffle
from PySide import QtCore, QtGui
class ClickableLabel(QtGui.QLabel):
clicked = QtCore.Signal(str)
def __init__(self, width, height, color):
super(ClickableLabel, self).__init__()
pixmap = QtGui.QPixmap(width, height)
pixmap.fill(QtGui.QColor(color))
self.setPixmap(pixmap)
self.setObjectName(color)
def mousePressEvent(self, event):
self.clicked.emit(self.objectName())
class Window(QtGui.QWidget):
def __init__(self):
QtGui.QWidget.__init__(self)
layout = QtGui.QGridLayout(self)
colors = 'red green blue orange purple yellow'.split()
for row in range(len(colors)):
shuffle(colors)
for column, color in enumerate(colors):
label = ClickableLabel(25, 25, color)
label.clicked.connect(self.handleLabelClicked)
layout.addWidget(label, row, column)
def handleLabelClicked(self, name):
print('"%s" clicked' % name)
if __name__ == '__main__':
import sys
app = QtGui.QApplication(sys.argv)
window = Window()
window.setGeometry(500, 300, 200, 200)
window.show()
sys.exit(app.exec_())
I guess the fast solution is subclass QLabel, use setPixmap() to put image on and reimplement mouseEvent() to submit signal clicked() on press/release event. As it is python (PyQt/PySide) then it should be just few lines. Usually I use such approach when need some graphics clickable.
Buttons are style able, and you can put images on them.

Resources