I don't know why but my 2 custom widgets(SquareCalc, LinePainting) when i use them in QXBoxLayout(twoWidgets) , there are being superimposed each other one.
I'm using python 3.5.2 with PyQt5
This is my code:
import sys
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QColor, QPainter, QPen
from PyQt5.QtWidgets import (QApplication, QWidget,
QGridLayout, QVBoxLayout, QHBoxLayout,QLabel, QLineEdit, QPushButton)
class SquareCalc(QWidget):
def __init__(self):
super().__init__()
def initUI(self):
self.setGeometry(0,0,100,100)
self.inputLine = QLineEdit()
self.outputLine = QLineEdit()
self.outputLine.setReadOnly(True)
self.inputLine.returnPressed.connect(self.calc)
self.calcButton = QPushButton("&Calc")
self.calcButton.clicked.connect(self.calc)
lineLayout = QGridLayout()
lineLayout.addWidget(QLabel("num"), 0, 0)
lineLayout.addWidget(self.inputLine, 0, 1)
lineLayout.addWidget(QLabel("result"), 1, 0)
lineLayout.addWidget(self.outputLine, 1, 1)
buttonLayout = QHBoxLayout()
buttonLayout.addWidget(self.calcButton)
mainLayout = QVBoxLayout()
mainLayout.addLayout(lineLayout)
mainLayout.addLayout(buttonLayout)
self.setLayout(mainLayout)
def calc(self):
n = int(self.inputLine.text())
r = n**2
self.outputLine.setText(str(r))
class LinePainting(QWidget):
def __init__(self):
super().__init__()
def initPainting(self):
self.setGeometry(0, 0, 300, 300)
self.setWindowTitle('Pen styles')
mainLayout = QVBoxLayout()
mainLayout.addWidget(self)
self.show()
def paintEvent(self, e):
qp = QPainter()
qp.begin(self)
self.drawLines(qp)
qp.end()
def drawLines(self, qp):
pen = QPen(Qt.black, 2, Qt.SolidLine)
qp.setPen(pen)
qp.drawLine(20, 40, 250, 40)
pen.setStyle(Qt.DashLine)
qp.setPen(pen)
qp.drawLine(20, 80, 250, 80)
pen.setStyle(Qt.DashDotLine)
qp.setPen(pen)
qp.drawLine(20, 120, 250, 120)
pen.setStyle(Qt.DotLine)
qp.setPen(pen)
qp.drawLine(20, 160, 250, 160)
pen.setStyle(Qt.DashDotDotLine)
qp.setPen(pen)
qp.drawLine(20, 200, 250, 200)
pen.setStyle(Qt.CustomDashLine)
pen.setDashPattern([1, 4, 5, 4])
qp.setPen(pen)
qp.drawLine(20, 240, 250, 240)
class twoWidget(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.widget1 = SquareCalc()
self.widget2 = LinePainting()
mainLayout = QHBoxLayout()
mainLayout.addWidget(self.widget1)
mainLayout.addWidget(self.widget2)
self.setLayout(mainLayout)
self.setWindowTitle("Mix line/factorial")
self.widget2.initPainting()
self.widget1.initUI()
self.show()
if __name__ == '__main__':
app = QApplication(sys.argv)
main_window = twoWidget()
main_window.setStyleSheet(open("lol.qss", "r").read())
main_window.show()
sys.exit(app.exec_())
I find the problem , i just need no put a fixed size to my widget SquareCalc,
just add
self.setFixedSize(sizeX,sizeY)
In replace of :
self.setGeometry(0, 0, 300, 300)
Just because QPainter no need to have a minimum size , on the contrary QLineEdit() and QPushButton(), yes
Related
How to animate position,scale or any other attributes of composed elements inside custom widget, on mouse pointer enters or leaves the QListWidgetItem ?
(see reference image below)
And is there any better way to manage space around ListWidgetItem ?
item_widget.sizeHint() gives unwanted extra space, which is why i added hard coded value to setSizeHint.
ProductMainWindow.py
from PySide2 import QtCore, QtGui, QtWidgets
import productThumbnailWidget
import sys
sys.path.append('E:/code')
class prodMainWindowUI(QtWidgets.QMainWindow):
def __init__(self):
QtWidgets.QMainWindow.__init__(self)
self.setupUi(self)
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(800, 600)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.verticalLayout = QtWidgets.QVBoxLayout(self.centralwidget)
self.verticalLayout.setObjectName("verticalLayout")
self.productListWidget = QtWidgets.QListWidget(self.centralwidget)
self.productListWidget.setObjectName("productListWidget")
self.productListWidget.setViewMode(QtWidgets.QListWidget.IconMode)
self.productListWidget.setIconSize(QtCore.QSize(256,256))
self.productListWidget.setResizeMode(QtWidgets.QListWidget.Adjust)
self.productListWidget.setMovement(QtWidgets.QListWidget.Static) # disable drag and drop
self.productListWidget.setGridSize(QtCore.QSize(256 + 5, 256 + 5))
self.verticalLayout.addWidget(self.productListWidget)
MainWindow.setCentralWidget(self.centralwidget)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
for i in range(6):
item = QtWidgets.QListWidgetItem(self.productListWidget)
item_widget = productThumbnailWidget.productThumbWidget()
#item.setSizeHint(item_widget.sizeHint())
item.setSizeHint(QtCore.QSize(256,256))
self.productListWidget.addItem(item)
self.productListWidget.setItemWidget(item, item_widget)
def retranslateUi(self, MainWindow):
MainWindow.setWindowTitle(QtWidgets.QApplication.translate("MainWindow", "MainWindow", None, -1))
app = QtWidgets.QApplication(sys.argv)
prodUI = prodMainWindowUI()
prodUI.show()
sys.exit(app.exec_())
productThumbnailWidget
from PySide2 import QtCore, QtGui, QtWidgets
class productThumbWidget(QtWidgets.QWidget):
def __init__(self, parent=None):
super(productThumbWidget, self).__init__(parent)
self.setObjectName("Form")
self.resize(256, 256)
self.setMinimumSize(QtCore.QSize(256, 256))
self.setMaximumSize(QtCore.QSize(256, 256))
self.verticalLayout = QtWidgets.QVBoxLayout()
self.verticalLayout.setContentsMargins(0, 0, 0, 0)
self.verticalLayout.setSpacing(0)
self.verticalLayout.setObjectName("verticalLayout")
self.frame = QtWidgets.QFrame()
self.frame.setFrameShape(QtWidgets.QFrame.StyledPanel)
self.frame.setFrameShadow(QtWidgets.QFrame.Raised)
self.frame.setObjectName("frame")
self.thumbnailLabel = QtWidgets.QLabel("", self.frame)
self.thumbnailLabel.setObjectName("thumbnailLabel")
self.thumbnailLabel.setScaledContents(False)
self.thumbnailLabel.setGeometry(QtCore.QRect(0, 0, 256, 256))
self.thumbnailLabel.setMinimumSize(QtCore.QSize(256, 256))
self.thumbnailLabel.setMaximumSize(QtCore.QSize(256, 256))
self.thumbnailLabel.setPixmap(QtGui.QPixmap("E:/code/android.png"))
self.backgroundLabel = QtWidgets.QLabel("", self.frame)
self.backgroundLabel.setObjectName("backgroundLabel")
self.backgroundLabel.setGeometry(QtCore.QRect(0, 206, 256, 50))
self.backgroundLabel.setMinimumSize(QtCore.QSize(256, 50))
self.backgroundLabel.setMaximumSize(QtCore.QSize(256, 50))
self.backgroundLabel.setStyleSheet("QLabel#backgroundLabel{\n"
" background: #32353B;\n"
"}")
self.titleLabel = QtWidgets.QLabel("Title", self.frame)
self.titleLabel.setObjectName("titleLabel")
self.titleLabel.setGeometry(QtCore.QRect(10, 218, 246, 25))
self.titleLabel.setMinimumSize(QtCore.QSize(246, 25))
self.titleLabel.setMaximumSize(QtCore.QSize(246, 25))
font = QtGui.QFont()
font.setFamily("SF Pro Display")
font.setPointSize(16)
font.setWeight(75)
font.setBold(True)
self.titleLabel.setFont(font)
self.titleLabel.setStyleSheet("QLabel#titleLabel {\n"
" color: #FFFFFF;\n"
"}")
self.verticalLayout.addWidget(self.frame)
self.setLayout(self.verticalLayout)
Output
The solution is to animate the position of the rectangle using QPropertyAnimation, and to activate the animations using the events QEvent::Enter and QEvent::Leave:
import shiboken2
from PySide2 import QtCore, QtGui, QtWidgets
class RectangleHoverEffect(QtCore.QObject):
def __init__(self, rectangle, parent):
super().__init__(parent)
if not isinstance(rectangle, QtWidgets.QWidget):
raise TypeError(f"{rectangle} must be a QWidget")
if rectangle.parent() is None:
raise ValueError(f"{rectangle} must have a parent")
self.m_rectangle = rectangle
self.m_rectangle.parent().installEventFilter(self)
self.m_animation = QtCore.QPropertyAnimation(
self,
targetObject=self.m_rectangle,
propertyName=b"pos",
duration=300,
easingCurve=QtCore.QEasingCurve.OutQuad,
)
def eventFilter(self, obj, event):
if shiboken2.isValid(self.m_rectangle):
if self.m_rectangle.parent() is obj:
y0 = self.m_rectangle.parent().height()
y1 = self.m_rectangle.parent().height() - self.m_rectangle.height()
if event.type() == QtCore.QEvent.Enter:
self._start_animation(y0, y1)
elif event.type() == QtCore.QEvent.Leave:
self._start_animation(y1, y0)
return super().eventFilter(obj, event)
def _start_animation(self, y0, y1):
self.m_animation.setStartValue(QtCore.QPoint(0, y0))
self.m_animation.setEndValue(QtCore.QPoint(0, y1))
self.m_animation.start()
class ThumbWidget(QtWidgets.QFrame):
def __init__(self, title, pixmap, parent=None):
super().__init__(parent)
self.setFrameShape(QtWidgets.QFrame.StyledPanel)
self.setFrameShadow(QtWidgets.QFrame.Raised)
pixmap_label = QtWidgets.QLabel(pixmap=pixmap, scaledContents=True)
title_label = QtWidgets.QLabel(title)
title_label.setStyleSheet("""color: #FFFFFF""")
font = QtGui.QFont()
font.setFamily("SF Pro Display")
font.setPointSize(16)
font.setWeight(75)
font.setBold(True)
title_label.setFont(font)
background_label = QtWidgets.QLabel(pixmap_label)
background_label.setStyleSheet("background: #32353B;")
background_label.setFixedSize(self.width(), 50)
background_label.move(0, self.height())
background_lay = QtWidgets.QVBoxLayout(background_label)
background_lay.addWidget(title_label)
self.setFixedSize(256, 256)
lay = QtWidgets.QVBoxLayout(self)
lay.setContentsMargins(0, 0, 0, 0)
lay.setSpacing(0)
lay.addWidget(pixmap_label)
effect = RectangleHoverEffect(background_label, self)
class ProductMainWindow(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super().__init__(parent)
self.product_listwidget = QtWidgets.QListWidget(
viewMode=QtWidgets.QListWidget.IconMode,
iconSize=QtCore.QSize(256, 256),
resizeMode=QtWidgets.QListWidget.Adjust,
movement=QtWidgets.QListWidget.Static,
)
self.product_listwidget.setGridSize(QtCore.QSize(256 + 5, 256 + 5))
for i in range(6):
item = QtWidgets.QListWidgetItem()
item_widget = ThumbWidget(f"Title {i}", QtGui.QPixmap("E:/code/android.png"))
item.setSizeHint(QtCore.QSize(256, 256))
self.product_listwidget.addItem(item)
self.product_listwidget.setItemWidget(item, item_widget)
central_widget = QtWidgets.QWidget()
self.setCentralWidget(central_widget)
lay = QtWidgets.QVBoxLayout(central_widget)
lay.addWidget(self.product_listwidget)
self.resize(960, 480)
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
w = ProductMainWindow()
w.show()
sys.exit(app.exec_())
I have a QFrame on my QWidget and after clicking QPushButton my
QFrame animates from (QRect(0, 0, 100, 100)) to (QRect(600, 500, 100,
100))
Question is: I want to know QFrame every x and y
position when it is animating
from PyQt5.QtWidgets import QWidget, QApplication, QFrame, QPushButton
from PyQt5.QtCore import QPropertyAnimation, QRect
from PyQt5.QtGui import QFont
import sys
class Example(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.setWindowTitle("Animation Window")
self.setGeometry(100, 100, 400, 400)
self.widgets()
self.show()
def widgets(self):
font = QFont("Times New Roman")
font.setPixelSize(20)
self.start = QPushButton("Start", self)
self.start.setFont(font)
self.start.setGeometry(100, 100, 100, 50)
self.start.clicked.connect(self.doAnimation)
self.frame = QFrame(self)
self.frame.setStyleSheet("background-color:darkGreen;")
self.frame.setFrameStyle(QFrame.Panel | QFrame.Raised)
self.frame.setGeometry(250, 100, 100, 100)
def doAnimation(self):
self.anim = QPropertyAnimation(self.frame, b"geometry")
self.anim.setDuration(10000)
self.anim.setStartValue(QRect(0, 0, 100, 100))
self.anim.setEndValue(QRect(600, 500, 100, 100))
self.anim.start()
if __name__ == "__main__":
app = QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
When an animation is running, it will trigger the signal valueChanged each time the animated value has changed:
def doAnimation(self):
self.anim = QPropertyAnimation(self.frame, b"geometry")
self.anim.valueChanged.connect(lambda: print(self.frame.pos()))
self.anim.setDuration(10000)
self.anim.setStartValue(QRect(0, 0, 100, 100))
self.anim.setEndValue(QRect(600, 500, 100, 100))
self.anim.start()
I have drawn a rectangle on QWidget after clicking push button rectangle moves from "LEFT TOP CORNER" to "RIGHT TOP CORNER"
How to move rectangle:
from "LEFT TOP CORNER" to "RIGHT TOP CORNER"
and "RIGHT TOP CORNER" to "RIGHT BOTTOM CORNER"
and "RIGHT BOTTOM CORNER" to "LEFT BOTTOM CORNER"
and "LEFT BOTTOM CORNER" to "LEFT TOP CORNER"
from PyQt5.QtWidgets import QWidget, QApplication, QFrame, QPushButton
from PyQt5.QtCore import QPropertyAnimation, QRect
from PyQt5.QtGui import QFont
import sys
class Example(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.setWindowTitle("Animation Window")
self.setGeometry(100, 100, 400, 400)
self.widgets()
self.show()
def widgets(self):
font = QFont("Times New Roman")
font.setPixelSize(20)
self.start = QPushButton("Start", self)
self.start.setFont(font)
self.start.setGeometry(100, 100, 100, 50)
self.start.clicked.connect(self.doAnimation)
self.frame = QFrame(self)
self.frame.setStyleSheet("background-color:darkGreen;")
self.frame.setFrameStyle(QFrame.Panel | QFrame.Raised)
self.frame.setGeometry(250, 100, 100, 100)
def doAnimation(self):
self.anim = QPropertyAnimation(self.frame, b"geometry")
self.anim.setDuration(10000)
self.anim.setStartValue(QRect(0, 0, 100, 100))
self.anim.setEndValue(QRect(1366, 0, 100, 100))
self.anim.start()
if __name__ == "__main__":
app = QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
Although using the finished signal is interesting, a more compact and scalable method is to use QSequentialAnimationGroup where you can concatenate animations that will run sequentially.
from PyQt5 import QtCore, QtGui, QtWidgets
class Example(QtWidgets.QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.setWindowTitle("Animation Window")
self.setGeometry(100, 100, 400, 400)
self.widgets()
self.show()
def widgets(self):
font = QtGui.QFont("Times New Roman")
font.setPixelSize(20)
self.start = QtWidgets.QPushButton("Start", self)
self.start.setFont(font)
self.start.setGeometry(100, 100, 100, 50)
# self.start.clicked.connect(self.doAnimation)
self.frame = QtWidgets.QFrame(self)
self.frame.setStyleSheet("background-color:darkGreen;")
self.frame.setFrameStyle(QtWidgets.QFrame.Panel | QtWidgets.QFrame.Raised)
self.frame.setGeometry(250, 100, 100, 100)
r = self.frame.rect()
rects = []
r.moveTopLeft(self.rect().topLeft())
rects.append(QtCore.QRect(r))
r.moveTopRight(self.rect().topRight())
rects.append(QtCore.QRect(r))
r.moveBottomRight(self.rect().bottomRight())
rects.append(QtCore.QRect(r))
r.moveBottomLeft(self.rect().bottomLeft())
rects.append(QtCore.QRect(r))
r.moveTopLeft(self.rect().topLeft())
rects.append(QtCore.QRect(r))
sequential_animation = QtCore.QSequentialAnimationGroup(self, loopCount=-1)
for rect_start, rect_end in zip(rects[:-1], rects[1:]):
animation = QtCore.QPropertyAnimation(
targetObject=self.frame,
propertyName=b"geometry",
startValue=rect_start,
endValue=rect_end,
duration=1000,
)
sequential_animation.addAnimation(animation)
self.start.clicked.connect(sequential_animation.start)
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
w = Example()
sys.exit(app.exec())
You can use signal to run next animation when first is finished
self.anim.finished.connect(self.doAnimation_2)
This code moves rectangle all time - last animation starts first animation.
from PyQt5.QtWidgets import QWidget, QApplication, QFrame, QPushButton
from PyQt5.QtCore import QPropertyAnimation, QRect
from PyQt5.QtGui import QFont
import sys
class Example(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.setWindowTitle("Animation Window")
self.setGeometry(100, 100, 400, 400)
self.widgets()
self.show()
def widgets(self):
font = QFont("Times New Roman")
font.setPixelSize(20)
self.start = QPushButton("Start", self)
self.start.setFont(font)
self.start.setGeometry(100, 100, 100, 50)
self.start.clicked.connect(self.doAnimation_1)
self.frame = QFrame(self)
self.frame.setStyleSheet("background-color:darkGreen;")
self.frame.setFrameStyle(QFrame.Panel | QFrame.Raised)
self.frame.setGeometry(250, 100, 100, 100)
def doAnimation_1(self):
self.anim = QPropertyAnimation(self.frame, b"geometry")
self.anim.setDuration(1000)
self.anim.setStartValue(QRect(0, 0, 100, 100))
self.anim.setEndValue(QRect(300, 0, 100, 100))
self.anim.finished.connect(self.doAnimation_2)
self.anim.start()
def doAnimation_2(self):
self.anim = QPropertyAnimation(self.frame, b"geometry")
self.anim.setDuration(1000)
self.anim.setStartValue(QRect(300, 0, 100, 100))
self.anim.setEndValue(QRect(300, 300, 100, 100))
self.anim.finished.connect(self.doAnimation_3)
self.anim.start()
def doAnimation_3(self):
self.anim = QPropertyAnimation(self.frame, b"geometry")
self.anim.setDuration(1000)
self.anim.setStartValue(QRect(300, 300, 100, 100))
self.anim.setEndValue(QRect(0, 300, 100, 100))
self.anim.finished.connect(self.doAnimation_4)
self.anim.start()
def doAnimation_4(self):
self.anim = QPropertyAnimation(self.frame, b"geometry")
self.anim.setDuration(1000)
self.anim.setStartValue(QRect(0, 300, 100, 100))
self.anim.setEndValue(QRect(0, 0, 100, 100))
self.anim.finished.connect(self.doAnimation_1)
self.anim.start()
if __name__ == "__main__":
app = QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
If you will have to run different animations in different moments then probably you could use QTimer
I'm trying to integrate a QMenubar in a QWidget in Pyside2 in Python3. It seems to be easier to integrate a QMenubar to a QMainWindow but I started the project with a QWidget and not a QMainWindow and this is why I would like to have a solution for a QWidget.
When I run the code, there is no error message but the menubar doesn't appear when I run the app. I checked that stackoveflow page but it didn't help me or I wasn't able to implement it.
Code
from PySide2.QtWidgets import (QWidget, QApplication, QGraphicsView,
QGridLayout)
from PySide2 import QtCore, QtWidgets, QtGui
from PySide2.QtOpenGL import *
from PySide2.QtCore import *
from PySide2.QtGui import *
image_path_str='image.jpg'
class View(QGraphicsView):
photo_clicked = QtCore.Signal(QtCore.QPoint)
def __init__(self, parent):
super(View, self).__init__()
self.scene = QtWidgets.QGraphicsScene(self)
self.photo = QtWidgets.QGraphicsPixmapItem()
self.scene.addItem(self.photo)
self.pixmap = QtGui.QPixmap(image_path_str)
self.photo.setPixmap(self.pixmap)
self.setScene(self.scene)
self.setDragMode(QGraphicsView.ScrollHandDrag)
class Window(QWidget):
def __init__(self):
super(Window, self).__init__()
self.view = View(self)
self.layout_contain_P1_P2 = QtWidgets.QGridLayout()
self.checkbox_P1= QtWidgets.QCheckBox("P1",self)
self.line_edit_P1_x = QtWidgets.QLineEdit(self)
self.line_edit_P1_x.setReadOnly(True)
self.line_edit_P1_y = QtWidgets.QLineEdit(self)
self.line_edit_P1_y.setReadOnly(True)
self.menubar = QtWidgets.QMenuBar()
self.archive = self.menubar.addMenu("archive")
self.menubar.setObjectName("menubar")
self.layout_contain_P1_P2.addWidget(self.checkbox_P1, 0, 0, Qt.AlignLeft)
self.grid_layout_P1_x_y = QtWidgets.QGridLayout()
self.grid_layout_P1_x_y.addWidget(self.line_edit_P1_x, 1, 0, Qt.AlignLeft)
self.grid_layout_P1_x_y.addWidget(self.line_edit_P1_y, 2, 0, Qt.AlignLeft)
self.layout_contain_P1_P2.addLayout(self.grid_layout_P1_x_y, 0, 1, 1, 1)
self.checkbox_P2 = QtWidgets.QCheckBox("P2",self)
self.line_edit_P2_x = QtWidgets.QLineEdit(self)
self.line_edit_P2_x.setReadOnly(True)
self.line_edit_P2_y = QtWidgets.QLineEdit(self)
self.line_edit_P2_y.setReadOnly(True)
self.layout_contain_P1_P2.addWidget(self.checkbox_P2, 1, 0, Qt.AlignLeft)
self.grid_layout_P2_x_y = QtWidgets.QGridLayout()
self.grid_layout_P2_x_y.addWidget(self.line_edit_P2_x, 0, 0, Qt.AlignLeft)
self.grid_layout_P2_x_y.addWidget(self.line_edit_P2_y, 1, 0, Qt.AlignLeft)
self.layout_contain_P1_P2.addLayout(self.grid_layout_P2_x_y, 1, 1, Qt.AlignLeft)
self.combo_box1 = QtWidgets.QComboBox(self)
self.combo_box1.addItem("measurements set 1")
self.combo_box1.addItem("measurements set 1")
self.combo_box2 = QtWidgets.QComboBox(self)
self.combo_box2.addItem("P1-P2")
self.combo_box2.addItem("P3-P4")
self.vertical1= QtWidgets.QVBoxLayout()
self.vertical1.addWidget(self.menubar)
self.vertical1.addWidget(self.combo_box1)
self.vertical1.addWidget(self.combo_box2)
self.vertical1.addLayout(self.layout_contain_P1_P2)
self.vertical2= QtWidgets.QVBoxLayout()
self.vertical2.addWidget(self.view)
self.horizontal= QtWidgets.QHBoxLayout()
self.horizontal.addLayout(self.vertical1)
self.horizontal.addLayout(self.vertical2)
self.setLayout(self.horizontal)
self.setWindowTitle("Image viewer")
self.setGeometry(200, 200, 1000, 800)
app = QApplication.instance()
if app is None:
app = QApplication([])
w = Window()
w.show()
w.raise_()
QApplication.setOverrideCursor(QCursor(Qt.CrossCursor))
app.exec_()
Here is screenshot of what I get:
Edit : not optimal workaround: add a QMainWindow class
Here is not optimal workaround. I had to add an extra class QMainWindow and call the Widget from within the QMainWindow
from PySide2.QtWidgets import (QWidget, QApplication, QGraphicsView,
QGridLayout, QMainWindow, QAction, QMenu)
from PySide2 import QtCore, QtWidgets, QtGui
from PySide2.QtOpenGL import *
from PySide2.QtCore import *
from PySide2.QtGui import *
image_path_str='image.jpg'
class View(QGraphicsView):
photo_clicked = QtCore.Signal(QtCore.QPoint)
def __init__(self, parent):
super(View, self).__init__()
self.scene = QtWidgets.QGraphicsScene(self)
self.photo = QtWidgets.QGraphicsPixmapItem()
self.scene.addItem(self.photo)
self.pixmap = QtGui.QPixmap(image_path_str)
self.photo.setPixmap(self.pixmap)
self.setScene(self.scene)
self.setDragMode(QGraphicsView.ScrollHandDrag)
class Window(QWidget):
def __init__(self):
super(Window, self).__init__()
self.view = View(self)
self.layout_contain_P1_P2 = QtWidgets.QGridLayout()
self.checkbox_P1= QtWidgets.QCheckBox("P1",self)
self.line_edit_P1_x = QtWidgets.QLineEdit(self)
self.line_edit_P1_x.setReadOnly(True)
self.line_edit_P1_y = QtWidgets.QLineEdit(self)
self.line_edit_P1_y.setReadOnly(True)
self.layout_contain_P1_P2.addWidget(self.checkbox_P1, 0, 0, Qt.AlignLeft)
self.grid_layout_P1_x_y = QtWidgets.QGridLayout()
self.grid_layout_P1_x_y.addWidget(self.line_edit_P1_x, 1, 0, Qt.AlignLeft)
self.grid_layout_P1_x_y.addWidget(self.line_edit_P1_y, 2, 0, Qt.AlignLeft)
self.layout_contain_P1_P2.addLayout(self.grid_layout_P1_x_y, 0, 1, 1, 1)
self.checkbox_P2 = QtWidgets.QCheckBox("P2",self)
self.line_edit_P2_x = QtWidgets.QLineEdit(self)
self.line_edit_P2_x.setReadOnly(True)
self.line_edit_P2_y = QtWidgets.QLineEdit(self)
self.line_edit_P2_y.setReadOnly(True)
self.layout_contain_P1_P2.addWidget(self.checkbox_P2, 1, 0, Qt.AlignLeft)
self.grid_layout_P2_x_y = QtWidgets.QGridLayout()
self.grid_layout_P2_x_y.addWidget(self.line_edit_P2_x, 0, 0, Qt.AlignLeft)
self.grid_layout_P2_x_y.addWidget(self.line_edit_P2_y, 1, 0, Qt.AlignLeft)
self.layout_contain_P1_P2.addLayout(self.grid_layout_P2_x_y, 1, 1, Qt.AlignLeft)
self.combo_box1 = QtWidgets.QComboBox(self)
self.combo_box1.addItem("measurements set 1")
self.combo_box1.addItem("measurements set 1")
self.combo_box2 = QtWidgets.QComboBox(self)
self.combo_box2.addItem("P1-P2")
self.combo_box2.addItem("P3-P4")
self.vertical1= QtWidgets.QVBoxLayout()
# self.vertical1.addWidget(self.menubar)
self.vertical1.addWidget(self.combo_box1)
self.vertical1.addWidget(self.combo_box2)
self.vertical1.addLayout(self.layout_contain_P1_P2)
self.vertical2= QtWidgets.QVBoxLayout()
self.vertical2.addWidget(self.view)
self.horizontal= QtWidgets.QHBoxLayout()
self.horizontal.addLayout(self.vertical1)
self.horizontal.addLayout(self.vertical2)
self.setLayout(self.horizontal)
self.setWindowTitle("Image viewer")
self.setGeometry(200, 200, 1000, 800)
class Main_window(QMainWindow):
def __init__(self, parent=None):
super(Main_window, self).__init__(parent)
self.window = Window()
self.setCentralWidget(self.window)
self.initUI()
def initUI(self):
menubar = self.menuBar()
fileMenu = menubar.addMenu('File')
impMenu = QMenu('Import', self)
impAct = QAction('Import mail', self)
impMenu.addAction(impAct)
newAct = QAction('New', self)
fileMenu.addAction(newAct)
fileMenu.addMenu(impMenu)
app = QApplication.instance()
if app is None:
app = QApplication([])
mw = Main_window()
mw.show()
mw.raise_()
QApplication.setOverrideCursor(QCursor(Qt.CrossCursor))
app.exec_()
I can not understand how to make the QPainter() draw inside a QLabel, here is the code I told would have worked:
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtGui import QPainter, QColor, QBrush
class Labella(QLabel):
def __init__(self, parent):
super().__init__()
lb = QLabel('text', parent)
lb.setStyleSheet('QFrame {background-color:grey;}')
lb.resize(200, 200)
qp = QPainter(lb)
qp.begin(lb);
qp.setBrush(QColor(200, 0, 0))
qp.drawRect(0,0,20,20);
qp.end();
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('#040404')
qp.setPen(col)
qp.setBrush(QColor(200, 0, 0))
qp.drawRect(10, 15, 200, 60)
class Example(QWidget):
def __init__(self):
super().__init__()
lb = Labella(self)
self.setGeometry(300, 300, 350, 300)
self.setWindowTitle('Colours')
self.show()
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
I can only find examples in C++ same as for the Qt documentation, please instruct me where I should have find the information if not here.
The documentation suggests to use QPainter inside the paintEvent.
By using the constructor like below, inside the method paintEvent, no need to call begin() and end()
(Your class Labella just miss a parameter to initialize the parent)
The method save() and restore() can be convenient to store a standard config of a QPainter, allowing to draw something different before restoring the settings.
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtGui import QPainter, QColor, QBrush
class Labella(QLabel):
def __init__(self, parent):
super().__init__(parent=parent)
self.setStyleSheet('QFrame {background-color:grey;}')
self.resize(200, 200)
def paintEvent(self, e):
qp = QPainter(self)
self.drawRectangles(qp)
qp.setBrush(QColor(200, 0, 0))
qp.drawRect(0,0,20,20)
def drawRectangles(self, qp):
qp.setBrush(QColor(255, 0, 0, 100))
qp.save() # save the QPainter config
qp.drawRect(10, 15, 20, 20)
qp.setBrush(QColor(0, 0, 255, 100))
qp.drawRect(50, 15, 20, 20)
qp.restore() # restore the QPainter config
qp.drawRect(100, 15, 20, 20)
class Example(QWidget):
def __init__(self):
super().__init__()
lb = Labella(self)
self.setGeometry(300, 300, 350, 300)
self.setWindowTitle('Colours')
self.show()
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())