How to implement a shape selection panel for rendering in PyQt5? - python

I'm designing graphic editor. As a scene for drawing, I need to use exactly QGraphicsScene. I implemented adding rectangles and ellipses to the scene with two buttons.
I need to implement dragging the faigures from the panel to the canvas, approximately as in the picture:Shape Selection Panel
What widgets or buttons can I use for this custom panel? Maybe there is an information an example with the implementation of a similar panel?
The program code with the implementation of adding shapes and the interface image:
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
import sys
# window class
class Window(QMainWindow):
def __init__(self):
super().__init__()
wid = QWidget()
self.setCentralWidget(wid)
# setting title
self.setWindowTitle("Paint with PyQt5")
# setting geometry to main window
self.setGeometry(100, 100, 800, 600)
# Defining a scene rect of 400x200, with it's origin at 0,0.
# If we don't set this on creation, we can set it later with .setSceneRect
self.scene = QGraphicsScene(0, 0, 400, 200)
# Set all items as moveable and selectable.
for item in self.scene.items():
item.setFlag(QGraphicsItem.ItemIsMovable)
item.setFlag(QGraphicsItem.ItemIsSelectable)
# Define our layout.
vbox = QVBoxLayout()
up = QPushButton("Rect")
up.clicked.connect(self.add_rect)
vbox.addWidget(up)
down = QPushButton("Elips")
down.clicked.connect(self.add_elips)
vbox.addWidget(down)
view = QGraphicsView(self.scene)
view.setRenderHint(QPainter.Antialiasing)
hbox = QHBoxLayout(self)
hbox.addLayout(vbox)
hbox.addWidget(view)
wid.setLayout(hbox)
def add_rect(self):
rect = QGraphicsRectItem(0, 0, 200, 50)
rect.setPos(50, 20)
rect.setFlag(QGraphicsItem.ItemIsMovable)
rect.setFlag(QGraphicsItem.ItemIsSelectable)
self.scene.addItem(rect)
def add_elips(self):
ellipse = QGraphicsEllipseItem(0, 0, 100, 100)
ellipse.setPos(75, 30)
ellipse.setFlag(QGraphicsItem.ItemIsMovable)
ellipse.setFlag(QGraphicsItem.ItemIsSelectable)
self.scene.addItem(ellipse)
# create pyqt5 app
App = QApplication(sys.argv)
# create the instance of our Window
window = Window()
# showing the window
window.show()
# start the app
sys.exit(App.exec())
Image of interface:
Image of interface

Related

How To Scroll in 'QMainWindow'

I've just starting to learn/use PyQt for my internship and am having some issues finding out how to add a scroll bar to this simple program:
class Window(QMainWindow):
def __init__(self):
super().__init__()
self.setGeometry(300,300,180,100)
self.button1= QPushButton(self)
self.button1.setText("Button 1")
self.button1.move(10,10)
self.button2= QPushButton(self)
self.button2.setText("Button 2")
self.button2.move(150,10)
if __name__ == '__main__':
app = QApplication(sys.argv)
window = Window()
window.show()
sys.exit(app.exec_())
Essentially, the window has a set size (here it's 180x100) but has elements outside of that size (i.e. button2 extents from 150 to 220 which makes it half outside of the 180px window)
Click-dragging the window larger shows the entirety of button2, which is fine, but I need a way to keep the window the size it is and just have a scroll bar to see all of the unseen items.
The QScrollArea class provides a scrolling view onto another widget.
More... https://doc.qt.io/qt-5/qscrollarea.html
A scroll area is used to display the contents of a child widget within a frame.
If the widget exceeds the size of the frame, the view can provide scroll bars so
that the entire area of the child widget can be viewed.
The child widget must be specified with setWidget().
import sys
from PyQt5.Qt import *
class Window(QMainWindow):
def __init__(self):
super().__init__()
self.setGeometry(300, 300, 180, 100)
self.scroll = QScrollArea()
self.widget = QWidget()
self.widget.resize(280, 200)
self.scroll.setWidget(self.widget)
self.button1= QPushButton(self.widget)
self.button1.setText("Button 1")
self.button1.move(10, 10)
self.button2= QPushButton(self.widget)
self.button2.setText("Button 2")
self.button2.move(150, 10)
self.setCentralWidget(self.scroll)
if __name__ == '__main__':
app = QApplication(sys.argv)
window = Window()
window.show()
sys.exit(app.exec_())

How to include folium map into PyQt5 application window?

I would like to ask how do I go about including a folium map into PyQt 5 window application such that the map does not take up the whole window. I have found a similar post on StackOverflow "How to show Folium map inside a PyQt5 GUI?", however, the solution code provided shown the folium map takes up the whole of the PyQt 5 window application.
So my question is how do I include the folium map but only takes up a portion of the PyQt 5 window application? As shown below, I am trying to include the map into the rectangle area. *The rectangle black box is drawn on paint for reference purposes.
FYI I have tried out the solution code from the StackOverflow post but I can't seem to be able to resize the map.
WANTED OUTPUT
CURRENT CODE FOR REFERENCE
from PyQt5.QtWidgets import QMainWindow, QApplication, QPushButton
from PyQt5 import QtWebEngineWidgets
import sys
from PyQt5 import QtGui
from PyQt5.QtCore import QRect
class Window(QMainWindow):
def __init__(self):
super().__init__()
self.title = "MAP PROJECT"
self.left = 200
self.top = 100
self.width = 1500
self.height = 800
self.initWindow()
def initWindow(self):
# set window title
self.setWindowTitle(self.title)
# set window geometry
# self.setGeometry(self.left, self.top, self.width, self.height)
# Disable PyQt 5 application from resizing
self.setFixedSize(self.width, self.height)
self.buttonUI()
self.show()
def buttonUI(self):
shortPathButton = QPushButton("Find shortest path", self)
# (set button location (x, x) set button size (y, y)
shortPathButton.setGeometry(QRect(30, 300, 120, 50))
button2 = QPushButton("Another path", self)
# (set button location (x, x) set button size (y, y)
button2.setGeometry(QRect(30, 370, 120, 50))
button3 = QPushButton("Another path", self)
# (set button location (x, x) set button size (y, y)
button3.setGeometry(QRect(30, 440, 120, 50))
# Below code is to connect the button to the function
# button.clicked.connect(self.ClickMe)
# Create function for shortest path (A* algorithm)
"""def ClickMe(self):
print("Hello World")"""
if __name__ == "__main__":
App = QApplication(sys.argv)
window = Window()
sys.exit(App.exec())
The problem has nothing to do with a QWebEngineView or folium but how to place widgets inside the window, if so, then a solution is to use layouts in this case I will use the following structure: First a central widget is established, inside this one QHBoxLayout , and in the QHBoxLayout a QWidget is added as a container to the left side where a QVBoxLayout will be placed where the buttons will be, and to the right side the QWebEngineView:
import io
import sys
import folium
from PyQt5 import QtCore, QtGui, QtWidgets, QtWebEngineWidgets
class Window(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
self.initWindow()
def initWindow(self):
self.setWindowTitle(self.tr("MAP PROJECT"))
self.setFixedSize(1500, 800)
self.buttonUI()
def buttonUI(self):
shortPathButton = QtWidgets.QPushButton(self.tr("Find shortest path"))
button2 = QtWidgets.QPushButton(self.tr("Another path"))
button3 = QtWidgets.QPushButton(self.tr("Another path"))
shortPathButton.setFixedSize(120, 50)
button2.setFixedSize(120, 50)
button3.setFixedSize(120, 50)
self.view = QtWebEngineWidgets.QWebEngineView()
self.view.setContentsMargins(50, 50, 50, 50)
central_widget = QtWidgets.QWidget()
self.setCentralWidget(central_widget)
lay = QtWidgets.QHBoxLayout(central_widget)
button_container = QtWidgets.QWidget()
vlay = QtWidgets.QVBoxLayout(button_container)
vlay.setSpacing(20)
vlay.addStretch()
vlay.addWidget(shortPathButton)
vlay.addWidget(button2)
vlay.addWidget(button3)
vlay.addStretch()
lay.addWidget(button_container)
lay.addWidget(self.view, stretch=1)
m = folium.Map(
location=[45.5236, -122.6750], tiles="Stamen Toner", zoom_start=13
)
data = io.BytesIO()
m.save(data, close_file=False)
self.view.setHtml(data.getvalue().decode())
if __name__ == "__main__":
App = QtWidgets.QApplication(sys.argv)
window = Window()
window.show()
sys.exit(App.exec())

How to create resizable layout UI in Pyqt?

I try to create a gui. The window should be resizable. When resized horizontally some of them widgets should expand and vertically too. I illustrated this to make it more clear:
Initial
horizontal resize
vertical resize
In Qt I use QHBoxLayout but without success unfortunately.
Thanks.
For Example :
You need to use the setStretchFactor method on your QSplitter
An example (modified from the QSplitter example Here):
import sys
from PyQt4 import QtGui, QtCore
class Example(QtGui.QWidget):
def __init__(self):
super(Example, self).__init__()
self.initUI()
def initUI(self):
hbox = QtGui.QHBoxLayout(self)
left = QtGui.QFrame(self)
left.setFrameShape(QtGui.QFrame.StyledPanel)
right = QtGui.QFrame(self)
right.setFrameShape(QtGui.QFrame.StyledPanel)
splitter = QtGui.QSplitter(QtCore.Qt.Horizontal)
splitter.addWidget(left)
splitter.addWidget(right)
splitter.setStretchFactor(1, 1)
splitter.setSizes([125, 150])
hbox.addWidget(splitter)
self.setLayout(hbox)
QtGui.QApplication.setStyle(QtGui.QStyleFactory.create('Cleanlooks'))
self.setGeometry(300, 300, 300, 200)
self.setWindowTitle('QtGui.QSplitter')
self.show()
def main():
app = QtGui.QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
This produces an initial UI that looks like this:
When the image is expanded horizontally, you can see that the left widget stays the same size:
When expanded vertically, both widgets expand:
Finally, the splitter is resizeable:
If you adjust the window size after adjusting the splitter, the left widget will retain it's size and the right will expand/collapse to fill the remainder of the window.

How to deal with layouts in PyQt4?

I want to display welcome label in middle of frame, how can I do that? It seems like layout problem as I googled but I haven't got final solution.
Here is the code:
import sys
from PyQt4.QtGui import *
from PyQt4.QtCore import *
class Window(QMainWindow):
def __init__(self):
super(Window, self).__init__()
palette = QPalette()
palette.setBrush(QPalette.Background, QBrush(QPixmap("Login page.jpg")))
self.setPalette(palette)
self.setWindowTitle("Login Frame")
self.setWindowIcon(QIcon('logo.png'))
self.setGeometry(50, 50, 500, 300)
self.setFixedSize(500, 300)
self.addWidgets()
def addWidgets(self):
self.lblWelcome = QLabel("Welcome to Railway e-Ticketing System", self)
self.lblWelcome.move(100,30)
wcFont = QFont("Open Sans", 25)
self.lblWelcome.setFont(wcFont)
self.lblUid = QLabel("User ID:", self)
self.lblUid.move(100,80)
font = QFont("Open Sans", 10)
self.lneUid = QLineEdit(self)
self.lneUid.setFont(font)
self.lneUid.setFixedHeight(25)
self.lneUid.setFixedWidth(200)
self.lneUid.move(225, 80)
self.lblPass = QLabel("Password:", self)
self.lblPass.move(100, 130)
self.lnePass = QLineEdit(self)
self.lnePass.setEchoMode(QLineEdit.Password)
self.lnePass.setFixedHeight(25)
self.lnePass.setFixedWidth(200)
self.lnePass.move(225, 130)
self.lblInvalid = QLabel("",self)
self.lblInvalid.move(100, 180)
self.btnLogin = QPushButton("Login",self)
#btnLogin.resize(btnLogin.sizeHint())
self.btnLogin.move(175, 230)
self.btnLogin.clicked.connect(self.authenticate)
#self.authenticate()
self.btnReg = QPushButton("Register", self)
self.btnReg.move(300, 230)
#btnReg.clicked.connect(register)
self.show()
def authenticate(self):
uid = self.lneUid.text()
upass = self.lnePass.text()
if(len(uid.strip()) == 0 or len(upass.strip()) == 0):
palette = QPalette()
palette.setColor(QPalette.Foreground, Qt.darkRed)
self.lblInvalid.setPalette(palette)
self.lblInvalid.setText("*Invalid credentials .")
else:
self.lblInvalid.setText("")
def main():
app = QApplication(sys.argv)
LoginWin = Window()
sys.exit(app.exec_())
if __name__ == "__main__":
main()
And here is the output:
You are using a QMainWindow which already has a layout with a central widget, a toolbar, a menu bar etc. The right way to use it is to define a central Widget, and put all your label and buttons in it. You didn't, so your label is not displayed properly.
But for your login frame, you clearly don't need all of this. You just need a QWidget:
import sys
from PyQt4 import QtCore,QtGui
class LoginFrame(QtGui.QWidget):
def __init__(self):
super(LoginFrame, self).__init__()
...
if __name__=='__main__':
app = QtGui.QApplication(sys.argv)
win = LoginFrame()
win.show()
sys.exit(app.exec_())
Your code should work with a QWidget, but I would still advise reading about box layout. Right now, you're using absolute positioning, which means you have to manually place your widget at a precise position, and you can't resize your window.
A box layout would be more flexible, and practical. For example you can use QFormLayout for the userID and password.
More about layouts on the ZetCode tutorial

Draggable window with pyqt4

just a simple question: I'm using pyqt4 to render a simple window. Here's the code, I post the whole thing so it easier to explain.
from PyQt4 import QtGui, QtCore, Qt
import time
import math
class FenixGui(QtGui.QWidget):
def __init__(self):
super(FenixGui, self).__init__()
# setting layout type
hboxlayout = QtGui.QHBoxLayout(self)
self.setLayout(hboxlayout)
# hiding title bar
self.setWindowFlags(QtCore.Qt.FramelessWindowHint)
# setting window size and position
self.setGeometry(200, 200, 862, 560)
self.setAttribute(Qt.Qt.WA_TranslucentBackground)
self.setAutoFillBackground(False)
# creating background window label
backgroundpixmap = QtGui.QPixmap("fenixbackground.png")
self.background = QtGui.QLabel(self)
self.background.setPixmap(backgroundpixmap)
self.background.setGeometry(0, 0, 862, 560)
# fenix logo
logopixmap = QtGui.QPixmap("fenixlogo.png")
self.logo = QtGui.QLabel(self)
self.logo.setPixmap(logopixmap)
self.logo.setGeometry(100, 100, 400, 150)
def main():
app = QtGui.QApplication([])
exm = FenixGui()
exm.show()
app.exec_()
if __name__ == '__main__':
main()
Now, you see that I put a background label in my window. I would like that the window could be dragged around the screen by dragging this label. I mean: you click on the label, you drag the label, and the whole window comes around the screen. Is this possible? I accept non-elegant ways as well, because as you can see I hid the title bar so it would be impossible to drag the window if I don't make it draggable via the background label.
Hope I explained my problem properly
Thank you very much!!
Matteo Monti
You can override mousePressEvent() and mouseMoveEvent() to get the location of the mouse cursor and move your widget to that location. mousePressEvent will give you the offset from the cursor position to the top left corner of your widget, and then you can calculate what the new position of the top left corner should be. You can add these methods to your FenixGui class.
def mousePressEvent(self, event):
self.offset = event.pos()
def mouseMoveEvent(self, event):
x=event.globalX()
y=event.globalY()
x_w = self.offset.x()
y_w = self.offset.y()
self.move(x-x_w, y-y_w)

Categories

Resources