I'm trying to create a custom PyQt5 button, but am running across problems displaying it in a QMainWindow object. Here's the code I'm trying:
import sys
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtWidgets import QMainWindow
class PicButton(QAbstractButton):
def __init__(self, pixmap, parent=None):
super(PicButton, self).__init__(parent)
self.pixmap = pixmap
def paintEvent(self, event):
painter = QPainter(self)
painter.drawPixmap(event.rect(), self.pixmap)
def sizeHint(self):
return self.pixmap.size()
class App(QMainWindow):
def __init__(self):
super().__init__()
self.left = 0
self.top = 0
self.width = 800
self.height = 800
self.initUI()
def initUI(self):
self.setGeometry(self.left, self.top, self.width, self.height)
self.setAutoFillBackground(True)
p = self.palette()
p.setColor(self.backgroundRole(), Qt.white)
self.setPalette(p)
btn = PicButton('/home/user/Desktop/Untitled.png')
btn.move(0, 0)
btn.resize(80,80)
self.show()
app = QApplication(sys.argv)
window = App()
The button will work if you just use window = Widget()and put the button object in there as is shown in this answer: how code a Image button in PyQt?
According to your code you must pass a QPixmap to your PicButton, In addition to them if you are going to move it should tell you where, if you pass the parent, it will place in that position relative to the father, but will not be drawn.
To solve the problem you must change:
btn = PicButton('/home/user/Desktop/Untitled.png')
to:
btn = PicButton(QPixmap('/home/user/Desktop/Untitled.png'), self)
Related
I've a problem with pyqt5. I've create a windows with a scene that has a background image, re-implementing drawBackground. I've also a button that allow me to add a line in a position on the scene. The problem is that if i click the button to draw the line, then this line is drawn in a separate scene with it's own background, instead of into the scene i have. Seems like it create a new scene to draw the line on. Here is my code:
import sys
from PyQt5 import QtGui
from PyQt5.QtGui import QImage
from PyQt5.QtWidgets import (QMainWindow, QGraphicsView, QPushButton,
QHBoxLayout, QVBoxLayout, QWidget, QApplication, QGraphicsScene)
class GraphicsScene(QGraphicsScene):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self._image = QImage()
#property
def image(self):
return self._image
#image.setter
def image(self, img):
self._image = img
self.update()
def drawBackground(self, painter, rect):
if self.image.isNull():
super().drawBackground(painter, rect)
else:
painter.drawImage(rect, self._image)
class MainWindow(QWidget):
def __init__(self):
super().__init__()
self.title = "parcelDeliveryIta";
self.top = 100
self.left = 100
self.width = 1500
self.height = 900
self.initUI()
def initUI(self):
self.scene = GraphicsScene(self)
self.scene._image = QImage('Italy.png')
view = QGraphicsView(self.scene, self)
self.scene.setSceneRect(0, 0, view.width(), view.height())
addLine = QPushButton('AddLine')
addLine.clicked.connect(self.addLine)
hbox = QHBoxLayout(self)
hbox.addWidget(view)
vbox = QVBoxLayout(self)
vbox.addWidget(addLine)
hbox.addLayout(vbox)
self.setWindowTitle(self.title)
self.setGeometry(self.top, self.left, self.width, self.height)
self.setFixedSize(self.width, self.height)
self.setLayout(hbox)
self.show()
def addLine(self):
self.scene.addLine(0, 0, 100, 100)
if __name__ == "__main__":
app = QApplication(sys.argv)
window = MainWindow()
sys.exit(app.exec_())
and this is the result when clicking the button:
As it is possible to see, the line is drawn with its own backgroung, that is image I've setted as background to the scene (the image above is cropped to show better the line)
Thanks for helping.
Explanation:
It seems that my previous solution is not suitable for your case since as the docs points out:
void QGraphicsScene::drawBackground(QPainter *painter, const
QRectF &rect) Draws the background of the scene using painter,
before any items and the foreground are drawn. Reimplement this
function to provide a custom background for the scene.
All painting is done in scene coordinates. The rect parameter is the
exposed rectangle.
If all you want is to define a color, texture, or gradient for the
background, you can call setBackgroundBrush() instead.
See also drawForeground() and drawItems().
(emphasis mine)
That paint will also be used to paint the base of the items and therefore caused that behavior.
Solution:
So you will have to resort to another solution, for example to use a QGraphicsPixmapItem as a base and readjust the size of the window with that information:
import sys
from PyQt5.QtGui import QPixmap
from PyQt5.QtWidgets import (
QGraphicsView,
QPushButton,
QHBoxLayout,
QVBoxLayout,
QWidget,
QApplication,
QGraphicsScene,
)
class GraphicsView(QGraphicsView):
def __init__(self, parent=None):
super().__init__(parent)
scene = QGraphicsScene(self)
self.setScene(scene)
self._pixmap_item = self.scene().addPixmap(QPixmap())
self._pixmap_item.setZValue(-1)
#property
def pixmap(self):
return self._pixmap_item.pixmap()
#pixmap.setter
def pixmap(self, pixmap):
self._pixmap_item.setPixmap(pixmap)
self.scene().setSceneRect(self._pixmap_item.boundingRect())
def resizeEvent(self, event):
if not self._pixmap_item.pixmap().isNull():
self.fitInView(self._pixmap_item)
super().resizeEvent(event)
class MainWindow(QWidget):
def __init__(self):
super().__init__()
self.title = "parcelDeliveryIta"
self.top = 100
self.left = 100
self.width = 1500
self.height = 900
self.initUI()
def initUI(self):
self.view = GraphicsView(self)
self.view.pixmap = QPixmap("Italy.png")
addLine = QPushButton("AddLine")
addLine.clicked.connect(self.addLine)
hbox = QHBoxLayout(self)
hbox.addWidget(self.view)
vbox = QVBoxLayout()
vbox.addWidget(addLine)
hbox.addLayout(vbox)
self.setWindowTitle(self.title)
self.setGeometry(self.top, self.left, self.width, self.height)
self.setFixedSize(self.width, self.height)
self.show()
def addLine(self):
self.view.scene().addLine(0, 0, 100, 100)
if __name__ == "__main__":
app = QApplication(sys.argv)
window = MainWindow()
sys.exit(app.exec_())
I have created a circle at random place in canvas, but I am unable to move or edit its properties like its label just by clicking and dragging it.
I want to create a circle that is movable by dragging and its properties like label are editable at any time please suggest the edits or new approach to do it. I am a beginner Please help...
import sys
from PyQt5 import QtWidgets
from PyQt5.QtWidgets import QApplication, QMainWindow,QPushButton,QWidget
from PyQt5 import QtGui
from PyQt5.QtCore import QRect,Qt
from PyQt5.QtGui import QPainter,QBrush, QPen
from PyQt5 import QtCore
from random import randint
class Window(QMainWindow):
def __init__(self):
super(Window,self).__init__()
title="layout management"
left=500
top=200
width=500
height=400
iconName="Ash.jpg"
self.setWindowTitle(title)
self.setWindowIcon(QtGui.QIcon(iconName))
self.setGeometry(left, top, width, height)
self.should_paint_circle = False
self.windowcomponents()
self.initUI()
self.show()
def initUI(self):
if self.should_paint_circle:
self.label=QtWidgets.QLabel(self)
self.label.setText('<h2>circle<h2>')
def windowcomponents(self):
button=QPushButton("Add", self)
button.setGeometry(QRect(0, 0, 50, 28))
button.setIcon(QtGui.QIcon("addbutton.png"))
button.setToolTip("<h3>This is for creating random circles<h3>")
button.clicked.connect(self.paintcircle)
button=QPushButton("Generate Report", self)
button.setGeometry(QRect(49,0,150,28))
button.setIcon(QtGui.QIcon("generatereport.png"))
button.setToolTip("This is for generating pdf report of connection between two circles")
button=QPushButton("Save", self)
button.setGeometry(QRect(199,0,120,28))
button.setIcon(QtGui.QIcon("saveicon.png"))
button.setToolTip("This is for saving an image of canvas area")
def paintEvent(self, event):
super().paintEvent(event)
if self.should_paint_circle:
painter = QtGui.QPainter(self)
painter.setRenderHint(QPainter.Antialiasing)
painter.setPen(QPen(Qt.black, 5, Qt.SolidLine))
painter.drawEllipse(randint(0,500), randint(0,500), 100, 100)
self.initUI()
self.label.move(60,100)
def paintcircle(self, painter):
self.should_paint_circle = True
self.update()
app = QApplication(sys.argv)
circle=Window()
circle.show()
sys.exit(app.exec_())
Image showing a circle at random position in window, its not draggable
The solution is similar, the code only changed in how to determine if the pressed point is inside the circle:
import random
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
class Window(QtWidgets.QMainWindow):
def __init__(self):
super(Window, self).__init__()
self.rect = QtCore.QRect()
self.drag_position = QtCore.QPoint()
button = QtWidgets.QPushButton("Add", self)
button.clicked.connect(self.on_clicked)
self.resize(640, 480)
#QtCore.pyqtSlot()
def on_clicked(self):
if self.rect.isNull():
self.rect = QtCore.QRect(
QtCore.QPoint(*random.sample(range(200), 2)), QtCore.QSize(100, 100)
)
self.update()
def paintEvent(self, event):
super().paintEvent(event)
if not self.rect.isNull():
painter = QtGui.QPainter(self)
painter.setRenderHint(QtGui.QPainter.Antialiasing)
painter.setPen(QtGui.QPen(QtCore.Qt.black, 5, QtCore.Qt.SolidLine))
painter.drawEllipse(self.rect)
def mousePressEvent(self, event):
if (
2 * QtGui.QVector2D(event.pos() - self.rect.center()).length()
< self.rect.width()
):
self.drag_position = event.pos() - self.rect.topLeft()
super().mousePressEvent(event)
def mouseMoveEvent(self, event):
if not self.drag_position.isNull():
self.rect.moveTopLeft(event.pos() - self.drag_position)
self.update()
super().mouseMoveEvent(event)
def mouseReleaseEvent(self, event):
self.drag_position = QtCore.QPoint()
super().mouseReleaseEvent(event)
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
Rect = Window()
Rect.show()
sys.exit(app.exec_())
I'm having trouble setting up PyQt on my own. My idea its to creat a music-player with a song title and album cover. I have had success in creating my own window and adding the album cover. But I can't add the label in the right position. I want the song title to be at the top-center of the window, like the image below:
I have tried a lot of ways, but had no luck.
import sys
from PyQt5.QtGui import QIcon, QPixmap, QFontDatabase, QFont
from PyQt5.QtWidgets import QApplication, QLabel, QMainWindow, QWidget, QGridLayout, QDialog
from PyQt5.QtCore import Qt, QRect
# Subclass QMainWindow to customise your application's main window
class MainWindow(QMainWindow):
def __init__(self, *args, **kwargs):
super(MainWindow, self).__init__(*args, **kwargs)
self.title = 'PyQt5 simple window - pythonspot.com'
self.left = 10
self.top = 10
self.width = 480
self.height = 320
self.initUI()
self.setWindowTitle("My Awesome App")
def add_font(self):
# Load the font:
font_db = QFontDatabase()
font_id = font_db.addApplicationFont('American Captain.ttf')
families = font_db.applicationFontFamilies(font_id)
ttf_font = QFont(' '.join(families), 15)
return ttf_font
def initUI(self):
ttf_font = self.add_font()
w = QWidget()
self.setWindowTitle(self.title)
self.setGeometry(self.left, self.top, self.width, self.height)
self.show()
album_cover = QLabel(self)
album_pic = QPixmap('resized_image.jpg')
album_cover.setPixmap(album_pic)
album_cover.setAlignment(Qt.AlignCenter)
self.setCentralWidget(album_cover)
art_alb = QLabel(self)
art_alb.setFont(ttf_font)
art_alb.setText("michael buble - christmas")
art_alb.setGeometry(self.x, self.y, self.x, self.y)
art_alb.setAlignment(Qt.AlignTop | Qt.AlignCenter )
art_alb.show()
self.show()
app = QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec_()
You should use a central widget with a layout to control how the child widgets are sized and positioned in the main window. Here is a re-write of your initUI method that should do what you want:
class MainWindow(QMainWindow):
...
def initUI(self):
self.setWindowTitle(self.title)
self.setGeometry(self.left, self.top, self.width, self.height)
widget = QWidget()
layout = QGridLayout(widget)
art_alb = QLabel(self)
ttf_font = self.add_font()
art_alb.setFont(ttf_font)
art_alb.setText("michael buble - christmas")
layout.addWidget(art_alb, 0, 0, Qt.AlignTop | Qt.AlignHCenter)
album_cover = QLabel(self)
album_pic = QPixmap('image.jpg')
album_cover.setPixmap(album_pic)
layout.addWidget(album_cover, 1, 0, Qt.AlignHCenter)
layout.setRowStretch(1, 1)
self.setCentralWidget(widget)
Note that there's no need to keep calling show(), since this is all handled automatically by the layout. For more information, see the Layout Management article in the Qt docs.
According to http://doc.qt.io/qt-5/qsizepolicy.html#Policy-enum, setting the size policy of a widget has the following effect:
The sizeHint() is a sensible size, but the widget can be shrunk and
still be useful. The widget can make use of extra space, so it should
get as much space as possible (e.g. the horizontal direction of a
horizontal slider).
So, I expect the Yellow widget below to fill up the Green widget, but that does not happen. What did I do wrong?
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
class Yellow(QWidget):
def __init__(self, *args):
super().__init__(*args)
# Set palette
bg = QPalette()
bg.setColor(QPalette.Window, Qt.yellow)
self.setAutoFillBackground(True)
self.setPalette(bg)
self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
class Green(QWidget):
def __init__(self, *args):
super().__init__(*args)
# Set palette
bg = QPalette()
bg.setColor(QPalette.Window, Qt.green)
self.setAutoFillBackground(True)
self.setPalette(bg)
self.yellow = Yellow(self)
class App(QMainWindow):
def __init__(self):
super().__init__()
self.title = 'PyQt5'
self.left = 10
self.top = 10
self.width = 200
self.height = 200
self.initUI()
def initUI(self):
self.setWindowTitle(self.title)
self.setGeometry(self.left, self.top, self.width, self.height)
self.green = Green(self)
self.green.resize(184, 154)
self.green.move(10, 10)
self.show()
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = App()
sys.exit(app.exec_())
Use a Layout:
class Green(QWidget):
def __init__(self, *args):
super().__init__(*args)
# Set palette
bg = QPalette()
bg.setColor(QPalette.Window, Qt.green)
self.setAutoFillBackground(True)
self.setPalette(bg)
self.yellow = Yellow(self)
self.myLayout = QGridLayout()
self.myLayout.addWidget(self.yellow)
self.setLayout(self.myLayout)
Result:
If you add self.myLayout.setContentsMargins(0,0,0,0) the yellow widget completely covers the green one:
I am working on a PyQt5 project, which needs a folder viewer by PyQt5 QTreeView. In order to put more stuff, I try to change the size of the tree view but in vain. Here is the code from Pythonspot:
import sys
from PyQt5.QtWidgets import QApplication, QFileSystemModel, QTreeView, QWidget, QVBoxLayout
from PyQt5.QtGui import QIcon
class App(QWidget):
def __init__(self):
super().__init__()
self.title = 'PyQt5 file system view - pythonspot.com'
self.left = 10
self.top = 10
self.width = 640
self.height = 480
self.initUI()
def initUI(self):
self.setWindowTitle(self.title)
self.setGeometry(self.left, self.top, self.width, self.height)
self.model = QFileSystemModel()
self.model.setRootPath('')
self.tree = QTreeView()
self.tree.setModel(self.model)
self.tree.setAnimated(False)
self.tree.setIndentation(20)
self.tree.setSortingEnabled(True)
self.tree.setWindowTitle("Dir View")
self.tree.resize(640, 200)
windowLayout = QVBoxLayout()
windowLayout.addWidget(self.tree)
self.setLayout(windowLayout)
self.show()
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = App()
sys.exit(app.exec_())
I change the tree view by
self.tree.resize(640, 200)
Why it does not function?
A layout is used to establish the position and size of the widget you are using, so in your case even if you use resize the size will not be changed, instead you should set a fixed size so the layout can not change the size of the QTreeView.
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
class App(QtWidgets.QWidget):
def __init__(self):
super().__init__()
self.title = 'PyQt5 file system view - pythonspot.com'
self.left, self.top, self.width, self.height = 10, 10, 640, 480
self.initUI()
def initUI(self):
self.setWindowTitle(self.title)
self.setGeometry(self.left, self.top, self.width, self.height)
self.model = QtWidgets.QFileSystemModel()
self.model.setRootPath('')
self.tree = QtWidgets.QTreeView()
self.tree.setModel(self.model)
self.tree.setAnimated(False)
self.tree.setIndentation(20)
self.tree.setSortingEnabled(True)
self.tree.setWindowTitle("Dir View")
self.tree.setFixedSize(640, 200)
windowLayout = QtWidgets.QVBoxLayout(self)
windowLayout.addWidget(self.tree, alignment=QtCore.Qt.AlignTop)
self.show()
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
ex = App()
sys.exit(app.exec_())