PyQt5: How to click a button to start the paint? - python

The following code makes a button and a rectangle. I would like to change it, so that the rectangle is drawn when the button is clicked.
from PyQt5.QtWidgets import QWidget, QApplication, QPushButton
from PyQt5.QtGui import QPainter, QColor, QBrush
import sys
class Example(QWidget):
def __init__(self):
super(Example, self).__init__()
self.initUI()
def initUI(self):
self.setFixedSize(400, 400)
self.setWindowTitle('Colours')
self.btn = QPushButton("Paint", self)
self.btn.move(100, 100)
# self.btn.clicked.connect(self.paintEvent())
self.show()
def paintEvent(self, e):
qp = QPainter()
qp.begin(self)
self.drawRectangles(qp)
qp.end()
def drawRectangles(self, qp):
col = QColor(0, 0, 0)
col.setNamedColor('#d4d4d4')
qp.setPen(col)
qp.setBrush(QColor(200, 0, 0))
qp.drawRect(10, 15, 90, 60)
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
Thanks for your help!

the paintEvent() method is called internally by Qt, it should not be called directly but through the update() method, but in your case you want to do it when a certain condition is used, before that you must create a flag that indicates that it should be drawn, all of the above is implemented in the following code:
class Example(QWidget):
def __init__(self):
super(Example, self).__init__()
self.initUI()
self.flag = False
def initUI(self):
self.setFixedSize(400, 400)
self.setWindowTitle('Colours')
self.btn = QPushButton("Paint", self)
self.btn.move(100, 100)
self.btn.clicked.connect(self.onClicked)
self.show()
def onClicked(self):
self.flag = True
self.update()
def paintEvent(self, e):
if self.flag:
qp = QPainter()
qp.begin(self)
self.drawRectangles(qp)
qp.end()
def drawRectangles(self, qp):
col = QColor(0, 0, 0)
col.setNamedColor('#d4d4d4')
qp.setPen(col)
qp.setBrush(QColor(200, 0, 0))
qp.drawRect(10, 15, 90, 60)

Related

PyQt5 stop timer inside a widget that was added from a different class

I would like to display the current date and time on the top of multiple windows, so I created a class of this top widget. It works, however when I switch to another window, the timer keeps running on the previous window too. How can I stop the timer right before switching window, perhaps keep the same instance running on the new window?
from PyQt5 import QtCore
from PyQt5 import QtWidgets
from PyQt5.QtWidgets import QApplication, QMainWindow, QHBoxLayout, QWidget
import sys
from datetime import datetime
CurrentWindow = None
class TopBar(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.labelTime = QtWidgets.QLabel(self)
self.labelTime.setStyleSheet("background-color: rgba(0, 0, 0, 0); color: white")
background = QtWidgets.QWidget(self)
background.setStyleSheet("background-color: rgba(0, 191, 255, 0.6)")
background.setGeometry(0, 0, 480, 30)
hbox = QHBoxLayout(background)
hbox.setContentsMargins(10, 0, 10, 0)
hbox.addWidget(self.labelTime, alignment=QtCore.Qt.AlignRight)
self.timer = QtCore.QTimer(self)
self.timer.setInterval(1000)
self.timer.timeout.connect(self.displayTime)
self.timer.start()
self.displayTime()
def displayTime(self):
print(self.parent())
self.labelTime.setText(datetime.now().strftime("%Y/%m/%d %H:%M:%S"))
class Window1(QMainWindow):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.resize(480, 320)
self.centralwidget = QtWidgets.QWidget(self)
self.setCentralWidget(self.centralwidget)
widgetTop = QtWidgets.QWidget(self.centralwidget)
widgetTop.setGeometry(0, 0, 480, 30)
layoutTop = QHBoxLayout(widgetTop)
layoutTop.addWidget(TopBar())
layoutTop.setContentsMargins(0, 0, 0, 0)
self.pushButton = QtWidgets.QPushButton(self.centralwidget)
self.pushButton.setText('Go to Window2')
self.pushButton.clicked.connect(self.goToWindow2)
layoutCenter = QHBoxLayout(self.centralwidget)
layoutCenter.addWidget(self.pushButton, alignment=QtCore.Qt.AlignCenter)
self.show()
def goToWindow2(self):
global CurrentWindow
CurrentWindow = Window2()
self.close()
class Window2(QMainWindow):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.resize(480, 320)
self.centralwidget = QtWidgets.QWidget(self)
self.setCentralWidget(self.centralwidget)
widgetTop = QtWidgets.QWidget(self.centralwidget)
widgetTop.setGeometry(0, 0, 480, 30)
layoutTop = QHBoxLayout(widgetTop)
layoutTop.addWidget(TopBar())
layoutTop.setContentsMargins(0, 0, 0, 0)
self.pushButton = QtWidgets.QPushButton(self.centralwidget)
self.pushButton.setText('Go to Window1')
self.pushButton.clicked.connect(self.goToWindow1)
layoutCenter = QHBoxLayout(self.centralwidget)
layoutCenter.addWidget(self.pushButton, alignment=QtCore.Qt.AlignCenter)
self.show()
def goToWindow1(self):
global CurrentWindow
CurrentWindow = Window1()
self.close()
if __name__=='__main__':
app = QApplication(sys.argv)
ex = Window1()
sys.exit(app.exec_())
I don't think that the QTimer execution slows down the application.
But I will still show you how to stop it from another window. To do this you must access the object so you must become a member of the class, and then when you change the window you stop it with the stop method of the QTimer.
class Window1(QMainWindow):
# ...
def initUI(self):
# ...
layoutTop = QHBoxLayout(widgetTop)
self.topbar = TopBar()
layoutTop.addWidget(self.topbar)
layoutTop.setContentsMargins(0, 0, 0, 0)
# ...
def goToWindow2(self):
global CurrentWindow
self.topbar.timer.stop()
CurrentWindow = Window2()
self.close()
class Window2(QMainWindow):
# ...
def initUI(self):
# ...
layoutTop = QHBoxLayout(widgetTop)
self.topbar = TopBar()
layoutTop.addWidget(self.topbar)
layoutTop.setContentsMargins(0, 0, 0, 0)
# ...
def goToWindow1(self):
global CurrentWindow
self.topbar.timer.stop()
CurrentWindow = Window1()
self.close()
If you still consider that the cause of the error is to have several QTimer then in the following code there will only be one TopBar and they will change the widget using a QStackedWidget
from PyQt5 import QtCore
from PyQt5 import QtWidgets
from PyQt5.QtWidgets import QApplication, QMainWindow, QHBoxLayout, QWidget
import sys
from datetime import datetime
class TopBar(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.setAttribute(QtCore.Qt.WA_StyledBackground)
self.labelTime = QtWidgets.QLabel()
self.labelTime.setStyleSheet("background-color: rgba(0, 0, 0, 0); color: white")
self.setStyleSheet("background-color: rgba(0, 191, 255, 0.6)")
self.setFixedHeight(30)
hbox = QHBoxLayout(self)
hbox.setContentsMargins(10, 0, 10, 0)
hbox.addWidget(self.labelTime, alignment=QtCore.Qt.AlignRight)
self.timer = QtCore.QTimer(self)
self.timer.setInterval(1000)
self.timer.timeout.connect(self.displayTime)
self.timer.start()
self.displayTime()
def displayTime(self):
self.labelTime.setText(datetime.now().strftime("%Y/%m/%d %H:%M:%S"))
class Window(QWidget):
changeWindow = QtCore.pyqtSignal(int)
def changeTo(self, index):
def callback():
self.changeWindow.emit(index)
return callback
class Window1(Window):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.pushButton = QtWidgets.QPushButton()
self.pushButton.setText("Go to Window2")
self.pushButton.clicked.connect(self.changeTo(1))
layoutCenter = QHBoxLayout(self)
layoutCenter.addWidget(self.pushButton, alignment=QtCore.Qt.AlignCenter)
class Window2(Window):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.pushButton = QtWidgets.QPushButton()
self.pushButton.setText("Go to Window1")
self.pushButton.clicked.connect(self.changeTo(0))
layoutCenter = QHBoxLayout(self)
layoutCenter.addWidget(self.pushButton, alignment=QtCore.Qt.AlignCenter)
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super().__init__(parent)
self.initUI()
def initUI(self):
self.resize(480, 320)
self.centralwidget = QtWidgets.QWidget(self)
self.setCentralWidget(self.centralwidget)
self.topbar = TopBar()
lay = QtWidgets.QVBoxLayout(self.centralwidget)
lay.setContentsMargins(0, 0, 0, 0)
lay.addWidget(self.topbar)
stacked_widget = QtWidgets.QStackedWidget()
lay.addWidget(stacked_widget)
for w in (Window1(), Window2()):
stacked_widget.addWidget(w)
if isinstance(w, Window):
w.changeWindow.connect(stacked_widget.setCurrentIndex)
if __name__ == "__main__":
app = QApplication(sys.argv)
w = MainWindow()
w.show()
sys.exit(app.exec_())

How to draw polyline with PyQt5 in Python?

I want to draw polyline with mouse event. But I can't set endpoints by clicking, or choose pen type. I want to draw linear lines, but when i write this code it only shows dots instead of drawing a line. Here is my code:
import sys
from PyQt5 import QtWidgets, QtCore
from PyQt5.QtGui import QPainter, QBrush, QColor, QPen, QPainterPath
from PyQt5.QtWidgets import QLabel, QGraphicsScene, QGraphicsView
class MyWidget(QtWidgets.QWidget):
def __init__(self):
super().__init__()
self.begin = QtCore.QPoint()
self.end = QtCore.QPoint()
self.beginList = []
self.endList = []
self.initUI()
def initUI(self):
self.setGeometry(200, 200, 1000, 500)
self.label = QLabel(self)
self.label.resize(500, 40)
self.show()
def paintEvent(self, event):
qp = QPainter(self)
for i,j in zip(self.beginList, self.endList):
qp.drawLines(QtCore.QLineF(i,j))
def mouseMoveEvent(self, event):
self.begin = event.pos()
self.end = event.pos()
self.beginList.append(self.begin)
self.endList.append(self.end)
self.label.setText('Coordinates: ( %d : %d )' % (event.x(), event.y()))
self.update()
def mouseReleaseEvent(self, event):
self.begin = event.pos()
self.end = event.pos()
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
window = MyWidget()
window.resize(800,600)
sys.exit(app.exec_())
If the OP code is analyzed, the starting point and the end point coincide, so when drawing a line between 2 points of the same location, only one point will be drawn. The logic is to join the point obtained in the i-th step with the (i+1)-th point.
To do the above the simplest thing is to use a QPainterPath:
import sys
from PyQt5 import QtWidgets, QtGui, QtCore
class MyWidget(QtWidgets.QWidget):
def __init__(self):
super().__init__()
self.initUI()
self.paths = []
def initUI(self):
self.setGeometry(200, 200, 1000, 500)
self.label = QtWidgets.QLabel(self)
self.show()
def paintEvent(self, event):
qp = QtGui.QPainter(self)
for path in self.paths:
qp.drawPath(path)
def mousePressEvent(self, event):
path = QtGui.QPainterPath()
path.moveTo(event.pos())
self.paths.append(path)
super().mousePressEvent(event)
def mouseMoveEvent(self, event):
self.paths[-1].lineTo(event.pos())
self.label.setText('Coordinates: ( %d : %d )' % (event.x(), event.y()))
self.label.adjustSize()
self.update()
super().mouseMoveEvent(event)
def mouseReleaseEvent(self, event):
self.paths[-1].lineTo(event.pos())
self.update()
super().mouseReleaseEvent(event)
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
window = MyWidget()
window.resize(800, 600)
sys.exit(app.exec_())

PyQt5: How to click a button to move the paint?

In the following code, one rectangle is made when the "Paint" button is clicked. It contains also a "Move" button. By clicking the "Move" button I want to move the rectangle 1px in both x and y directions. But I failed here.
I can understand the question is about how to transfer variable values wenn a button is clicked. To a beginner it is very difficult for me. Any help will be highly appreciated!
# -*- coding: utf-8 -*-
from PyQt5.QtWidgets import QWidget, QApplication, QPushButton, QHBoxLayout, QDoubleSpinBox
from PyQt5.QtGui import QPainter, QColor, QBrush
import sys
class Example(QWidget):
def __init__(self):
super(Example, self).__init__()
self.initUI()
self.flag = False
def initUI(self):
self.setFixedSize(400, 400)
self.setWindowTitle('Colours')
self.btnPaint = QPushButton("Paint", self)
self.btnMove = QPushButton("Move x+1 y+1", self)
self.deltax = 0 # original value
self.deltay = 0 # original value
self.btnPaint.clicked.connect(self.onPaint)
self.btnMove.clicked.connect(self.onMove)
self.hlayout = QHBoxLayout()
self.hlayout.addWidget(self.btnPaint)
self.hlayout.addWidget(self.btnMove)
self.hlayout.addStretch(1)
self.setLayout(self.hlayout)
self.show()
def onPaint(self):
self.flag = True
self.update()
def onMove(self):
self.deltax = self.deltax + 1 # button clicked, value +1
self.deltay = self.deltay + 1 # button clicked, value +1
self.flag_move = True
self.update()
def paintEvent(self, e):
if self.flag:
qp = QPainter()
qp.begin(self)
self.drawRectangles(qp)
qp.end()
if self.flag_move:
qp = QPainter()
qp.begin(self)
self.drawRectangles(qp)
qp.end()
def drawRectangles(self, qp):
x1 = 10
y1 = 15
x2 = 90
y2 = 60
col = QColor(0, 0, 0)
col.setNamedColor('#d4d4d4')
qp.setPen(col)
qp.setBrush(QColor(200, 0, 0))
qp.drawRect(x1+self.deltax, y1+self.deltay, x2+self.deltax, y2+self.deltay)
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
Your code has an error because the self.flag_move is not initially defined, but it is not necessary to use so many variables either.
Qt has the QRect class that has several methods that make the task easier, initially we create a null QRect, and when the btnPaint button is pressed we will enable QRect to a non-null one. in the case of pressing the btnMove button we will use the translate method that moves the rectangle:
import sys
from PyQt5.QtWidgets import QWidget, QApplication, QPushButton, QHBoxLayout
from PyQt5.QtGui import QPainter, QColor, QBrush
from PyQt5.QtCore import QRect, QPoint
class Example(QWidget):
def __init__(self):
super(Example, self).__init__()
self.initUI()
def initUI(self):
self.setFixedSize(400, 400)
self.setWindowTitle('Colours')
self.btnPaint = QPushButton("Paint", self)
self.btnMove = QPushButton("Move x+1 y+1", self)
self.rect = QRect()
self.btnPaint.clicked.connect(self.onPaint)
self.btnMove.clicked.connect(self.onMove)
self.hlayout = QHBoxLayout(self)
self.hlayout.addWidget(self.btnPaint)
self.hlayout.addWidget(self.btnMove)
self.hlayout.addStretch(1)
self.show()
def onPaint(self):
if self.rect.isNull():
self.rect = QRect(10, 15, 80, 45)
self.update()
def onMove(self):
if not self.rect.isNull():
self.rect.translate(QPoint(1, 1))
self.update()
def paintEvent(self, e):
qp = QPainter(self)
qp.setPen(QColor("#d4d4d4"))
qp.setBrush(QColor(200, 0, 0))
qp.drawRect(self.rect)

PySide/PyQT5: How to emit signals from a QGraphicsItem?

I want to emit a signal from a QGraphicsItem when it is doubled-clicked, in order to change a widget in the main window. The graphics-scene/-item does not provide an emit() method, but I was just wondering if there is an alternate way to do this. The code below has a function within a QGraphicsView class that will print to the terminal when an item is double-clicked. How can I make that into a slot/signal instead (if QGraphicsItem does not support signal/slots)?
import sys
from PySide.QtCore import *
from PySide.QtGui import *
class MyFrame(QGraphicsView):
def __init__( self, parent = None ):
super(MyFrame, self).__init__(parent)
scene = QGraphicsScene()
self.setScene(scene)
self.setFixedSize(500, 500)
pen = QPen(QColor(Qt.green))
brush = QBrush(pen.color().darker(150))
item = scene.addEllipse(0, 0, 45, 45, pen, brush)
item.setPos(0,0)
def mouseDoubleClickEvent(self, event):
print("Circle Clicked!")
# this double click event prints to terminal but how to setup
# signal/slot to update the QWidget QLabel text instead?
class Example(QWidget):
def __init__(self):
super(Example, self).__init__()
self.initUI()
def initUI(self):
hbox = QHBoxLayout(self)
top = QLabel("Double Click Green Circle (Howto change this QWidget Label with signals?)")
bottom = MyFrame()
splitter = QSplitter(Qt.Vertical)
splitter.addWidget(top)
splitter.addWidget(bottom)
hbox.addWidget(splitter)
self.setLayout(hbox)
self.setGeometry(0, 0, 500, 600)
self.show()
def main():
app = QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
Below is a simple example showing one way to emit signals from a graphics-item. This defines a custom signal on a subclass of QGraphicsScene and then uses the scene() method of graphics-items to emit it:
import sys
from PySide import QtCore, QtGui
class GraphicsScene(QtGui.QGraphicsScene):
itemDoubleClicked = QtCore.Signal(object)
class GraphicsRectangle(QtGui.QGraphicsRectItem):
def mouseDoubleClickEvent(self, event):
self.scene().itemDoubleClicked.emit(self)
class Window(QtGui.QWidget):
def __init__(self):
super(Window, self).__init__()
self.view = QtGui.QGraphicsView()
self.scene = GraphicsScene(self)
self.view.setScene(self.scene)
layout = QtGui.QVBoxLayout(self)
layout.addWidget(self.view)
for i in range(1, 4):
self.scene.addItem(GraphicsRectangle(50 * i, 50 * i, 20, 20))
self.scene.itemDoubleClicked.connect(self.handleItemDoubleClicked)
def handleItemDoubleClicked(self, item):
print(item.boundingRect())
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
window = Window()
window.setGeometry(600, 100, 300, 200)
window.show()
sys.exit(app.exec_())
UPDATE:
Below is a an example based on the code in your question. The basic idea is the same: define a custom signal on an available QObject (the graphics-view in this case), and use that to emit the double-click notification.
import sys
from PySide.QtCore import *
from PySide.QtGui import *
class MyFrame(QGraphicsView):
itemDoubleClicked = Signal(object)
def __init__(self, parent=None):
super(MyFrame, self).__init__(parent)
scene = QGraphicsScene()
self.setScene(scene)
self.setFixedSize(500, 500)
for i, color in enumerate('red blue green'.split()):
pen = QPen(QColor(color))
brush = QBrush(pen.color().darker(150))
item = scene.addEllipse(i * 50, i * 50, 45, 45, pen, brush)
item.setData(0, color.upper())
def mouseDoubleClickEvent(self, event):
item = self.itemAt(event.pos())
if item is not None:
self.itemDoubleClicked.emit(item)
class Example(QWidget):
def __init__(self):
super(Example, self).__init__()
self.initUI()
def initUI(self):
hbox = QHBoxLayout(self)
top = QLabel('Double Click a Circle')
bottom = MyFrame()
bottom.itemDoubleClicked.connect(
lambda item, top=top:
top.setText('Double Clicked: %s' % item.data(0)))
splitter = QSplitter(Qt.Vertical)
splitter.addWidget(top)
splitter.addWidget(bottom)
hbox.addWidget(splitter)
self.setLayout(hbox)
self.setGeometry(0, 0, 500, 600)
self.show()
def main():
app = QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
if __name__ == '__main__':
main()

PySide/PyQt Overlay widget

I am trying to achieve something like this in PySide: https://codepen.io/imprakash/pen/GgNMXO
What I want to do is create a child window frameless with a black overlay below.
I didn't succeed to create a child window frameless and the overlay...
This is a base code to replicate the HTML:
from PySide import QtCore, QtGui
import sys
class MainWindow(QtGui.QWidget):
def __init__(self):
QtGui.QWidget.__init__(self)
self.resize(800, 500)
self.button = QtGui.QPushButton("Click Me")
self.setLayout(QtGui.QVBoxLayout())
self.layout().addWidget(self.button)
# Connections
self.button.clicked.connect(self.displayOverlay)
def displayOverlay(self):
popup = QtGui.QDialog(self)
popup.setWindowFlags(QtCore.Qt.FramelessWindowHint)
popup.setLayout(QtGui.QHBoxLayout())
popup.layout().addWidget(QtGui.QLabel("HI"))
popup.show()
print "clicked"
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())
If you comment the line with the FramelessWindowHint, the window comes, else nothing happen...
I really hope that someone could help me. Thank you for the time you spent to read my question.
I'll be using PyQt5 for this explanation. It might have some differences to PySide (which I'm not sure if its still maintained) and PyQt4, but it shouldn't be too hard to convert.
The following example has a parent widget which a few buttons. One of them (the obvious one) calls for the popup. I've prepared the example to deal with the parent resize but have not made any code regarding mouse events of dragging the popup (see mouseMoveEvent and mouseReleaseEvent for that).
So here is the code:
import sys
from PyQt5 import QtWidgets, QtCore, QtGui
class TranslucentWidgetSignals(QtCore.QObject):
# SIGNALS
CLOSE = QtCore.pyqtSignal()
class TranslucentWidget(QtWidgets.QWidget):
def __init__(self, parent=None):
super(TranslucentWidget, self).__init__(parent)
# make the window frameless
self.setWindowFlags(QtCore.Qt.FramelessWindowHint)
self.setAttribute(QtCore.Qt.WA_TranslucentBackground)
self.fillColor = QtGui.QColor(30, 30, 30, 120)
self.penColor = QtGui.QColor("#333333")
self.popup_fillColor = QtGui.QColor(240, 240, 240, 255)
self.popup_penColor = QtGui.QColor(200, 200, 200, 255)
self.close_btn = QtWidgets.QPushButton(self)
self.close_btn.setText("x")
font = QtGui.QFont()
font.setPixelSize(18)
font.setBold(True)
self.close_btn.setFont(font)
self.close_btn.setStyleSheet("background-color: rgb(0, 0, 0, 0)")
self.close_btn.setFixedSize(30, 30)
self.close_btn.clicked.connect(self._onclose)
self.SIGNALS = TranslucentWidgetSignals()
def resizeEvent(self, event):
s = self.size()
popup_width = 300
popup_height = 120
ow = int(s.width() / 2 - popup_width / 2)
oh = int(s.height() / 2 - popup_height / 2)
self.close_btn.move(ow + 265, oh + 5)
def paintEvent(self, event):
# This method is, in practice, drawing the contents of
# your window.
# get current window size
s = self.size()
qp = QtGui.QPainter()
qp.begin(self)
qp.setRenderHint(QtGui.QPainter.Antialiasing, True)
qp.setPen(self.penColor)
qp.setBrush(self.fillColor)
qp.drawRect(0, 0, s.width(), s.height())
# drawpopup
qp.setPen(self.popup_penColor)
qp.setBrush(self.popup_fillColor)
popup_width = 300
popup_height = 120
ow = int(s.width()/2-popup_width/2)
oh = int(s.height()/2-popup_height/2)
qp.drawRoundedRect(ow, oh, popup_width, popup_height, 5, 5)
font = QtGui.QFont()
font.setPixelSize(18)
font.setBold(True)
qp.setFont(font)
qp.setPen(QtGui.QColor(70, 70, 70))
tolw, tolh = 80, -5
qp.drawText(ow + int(popup_width/2) - tolw, oh + int(popup_height/2) - tolh, "Yep, I'm a pop up.")
qp.end()
def _onclose(self):
print("Close")
self.SIGNALS.CLOSE.emit()
class ParentWidget(QtWidgets.QWidget):
def __init__(self, parent=None):
super(ParentWidget, self).__init__(parent)
self._popup = QtWidgets.QPushButton("Gimme Popup!!!")
self._popup.setFixedSize(150, 40)
self._popup.clicked.connect(self._onpopup)
self._other1 = QtWidgets.QPushButton("A button")
self._other2 = QtWidgets.QPushButton("A button")
self._other3 = QtWidgets.QPushButton("A button")
self._other4 = QtWidgets.QPushButton("A button")
hbox = QtWidgets.QHBoxLayout()
hbox.addWidget(self._popup)
hbox.addWidget(self._other1)
hbox.addWidget(self._other2)
hbox.addWidget(self._other3)
hbox.addWidget(self._other4)
self.setLayout(hbox)
self._popframe = None
self._popflag = False
def resizeEvent(self, event):
if self._popflag:
self._popframe.move(0, 0)
self._popframe.resize(self.width(), self.height())
def _onpopup(self):
self._popframe = TranslucentWidget(self)
self._popframe.move(0, 0)
self._popframe.resize(self.width(), self.height())
self._popframe.SIGNALS.CLOSE.connect(self._closepopup)
self._popflag = True
self._popframe.show()
def _closepopup(self):
self._popframe.close()
self._popflag = False
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
main = ParentWidget()
main.resize(500, 500)
main.show()
sys.exit(app.exec_())
Which results in the following:
The logic is the following. You create an empty Widget and manually draw the background and popup (paintEvent). You add a button for closing the popup. For this you build a Signal and let the parent widget do the closing. This is important because you need to make the parent widget control some important elements of the popup (such as closing, resizng, etc.). You can add far more complexity but hopefully the example will suffice for starters.
Thanks to armatita, I succeed to get what I wanted. For now, there are some issues but it works and I get the result that I wanted.
I give you the code to the next who will be looking for the same thing.
from PySide import QtCore, QtGui
import sys
class CtmWidget(QtGui.QWidget):
def __init__(self, parent = None):
QtGui.QWidget.__init__(self, parent)
self.button = QtGui.QPushButton("Close Overlay")
self.setLayout(QtGui.QHBoxLayout())
self.layout().addWidget(self.button)
self.button.clicked.connect(self.hideOverlay)
def paintEvent(self, event):
painter = QtGui.QPainter()
painter.begin(self)
painter.setRenderHint(QtGui.QPainter.Antialiasing)
path = QtGui.QPainterPath()
path.addRoundedRect(QtCore.QRectF(self.rect()), 10, 10)
mask = QtGui.QRegion(path.toFillPolygon().toPolygon())
pen = QtGui.QPen(QtCore.Qt.white, 1)
painter.setPen(pen)
painter.fillPath(path, QtCore.Qt.white)
painter.drawPath(path)
painter.end()
def hideOverlay(self):
self.parent().hide()
class Overlay(QtGui.QWidget):
def __init__(self, parent, widget):
QtGui.QWidget.__init__(self, parent)
palette = QtGui.QPalette(self.palette())
palette.setColor(palette.Background, QtCore.Qt.transparent)
self.setPalette(palette)
self.widget = widget
self.widget.setParent(self)
def paintEvent(self, event):
painter = QtGui.QPainter()
painter.begin(self)
painter.setRenderHint(QtGui.QPainter.Antialiasing)
painter.fillRect(event.rect(), QtGui.QBrush(QtGui.QColor(0, 0, 0, 127)))
painter.end()
def resizeEvent(self, event):
position_x = (self.frameGeometry().width()-self.widget.frameGeometry().width())/2
position_y = (self.frameGeometry().height()-self.widget.frameGeometry().height())/2
self.widget.move(position_x, position_y)
event.accept()
class MainWindow(QtGui.QWidget):
def __init__(self):
QtGui.QWidget.__init__(self)
self.resize(800, 500)
self.button = QtGui.QPushButton("Click Me")
self.setLayout(QtGui.QVBoxLayout())
self.layout().addWidget(self.button)
self.popup = Overlay(self, CtmWidget())
self.popup.hide()
# Connections
self.button.clicked.connect(self.displayOverlay)
def displayOverlay(self):
self.popup.show()
print "clicked"
def resizeEvent(self, event):
self.popup.resize(event.size())
event.accept()
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())
Once again thank you both of you(ymmx and armatita) to spend time on my issue.
did you try replacing popup.show() by popup.exec_()? and remove self as a parameter of the Qdialog? I change QDialog to QmessageBox to be able to quit the subwindow but it still work with the QDialog.
popup = QMessageBox()
popup.setWindowFlags( Qt.FramelessWindowHint)
popup.setLayout( QHBoxLayout())
popup.layout().addWidget( QLabel("HI"))
popup.exec_()
update
class Popup(QDialog ):
def __init__(self):
super().__init__()
self.setWindowFlags( Qt.CustomizeWindowHint)
self.setLayout( QHBoxLayout())
Button_close = QPushButton('close')
self.layout().addWidget( QLabel("HI"))
self.layout().addWidget( Button_close)
Button_close.clicked.connect( self.close )
self.exec_()
print("clicked")
def mousePressEvent(self, event):
self.oldPos = event.globalPos()
def mouseMoveEvent(self, event):
delta = QPoint (event.globalPos() - self.oldPos)
#print(delta)
self.move(self.x() + delta.x(), self.y() + delta.y())
self.oldPos = event.globalPos()
class MainWindow( QWidget):
def __init__(self):
QWidget.__init__(self)
self.resize(800, 500)
self.button = QPushButton("Click Me")
self.setLayout( QVBoxLayout())
self.layout().addWidget(self.button)
# Connections
self.button.clicked.connect(self.displayOverlay)
def displayOverlay(self):
Popup( )
if __name__ == "__main__":
app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())

Categories

Resources