I have a basic GUI window, created with pyqt5 package, that contain a button that once clicked opens a map window thanks to Python's pyqtlet package.
My program does open the map window on first click, but here my issue:
If I close the map window and click again on the button it only show me a white window.
SOURCE CODE
import sys
from PyQt5.QtWidgets import QApplication, QWidget, QPushButton, QGridLayout
from PyQt5.QtCore import Qt
from pyqtlet import L, MapWidget
class MainWindow(QWidget):
def __init__(self):
super().__init__()
# set window title
self.setWindowTitle('Windowtitle')
# set layout
self.layout = QGridLayout()
self.layout.setAlignment(Qt.AlignCenter)
# create button to show the map
self.show_map_button = QPushButton('Show Map')
self.show_map_button.clicked.connect(self.show_map)
# add button to layout
self.layout.addWidget(self.show_map_button, 0, 1)
# show layout
self.setLayout(self.layout)
self.my_map = None
def show_map(self):
# create map window instance
self.my_map = MapWindow()
class MapWindow(QWidget):
def __init__(self):
# Setting up the widgets and layout
super().__init__()
self.mapWidget = MapWidget()
self.layout = QGridLayout()
self.layout.addWidget(self.mapWidget)
self.setLayout(self.layout)
# Working with the maps with pyqtlet
self.map = L.map(self.mapWidget)
self.map.setView([12.97, 77.59], 10)
L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png').addTo(self.map)
self.marker = L.marker([12.934056, 77.610029])
self.marker.bindPopup('Maps are a treasure.')
self.map.addLayer(self.marker)
self.show()
if __name__ == "__main__":
app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())
I click the button for the first time (works as expected):
The second time I click it doesn't work as expected:
Please, can you help me find out where the issue is?
You are not trying to reopen the window but you are creating a new window but pyqtleft only allows you to register a "map" object. So if you want to reopen the window after the user closed it then check that if the object exists then just use the show method:
def show_map(self):
if self.my_map is None:
# create map window instance
self.my_map = MapWindow()
else:
self.my_map.show()
Related
I am going to build a simple app using QTabWidet, I added tool bar inside it, but the problem is that when I add new tab, the toolbar show on that tab but when I go to the previous tab, the toolbar disappear. What is the problem kindly help me to solve this issue.
Code and Pictures given below.
from PySide2.QtWidgets import*
from PySide2.QtWebEngineWidgets import*
from PySide2.QtCore import QUrl,Qt
class mainwindow(QMainWindow):
def __init__(self):
super().__init__()
self.tabs = QTabWidget(self)
self.tabs.setDocumentMode(True)
self.tabs.tabBarDoubleClicked.connect(self.open_newTab)
action1 = QAction("tool1",self)
action2 = QAction("tool2",self)
action3 = QAction("tool3")
self.toolbar = QToolBar("title")
# v.addWidget(toolbar)
self.toolbar.addAction(action1)
# toolbar.setFixedHeight(30)
self.toolbar.addAction(action2)
self.toolbar.addAction(action3)
self.setCentralWidget(self.tabs)
self.add_new_tab()
self.toolbar.setStyleSheet("background:green;")
def add_new_tab(self,widget=None,label="Blank"):
w = QWidget()
v = QVBoxLayout()
v.addWidget(self.toolbar)
v.setContentsMargins(0,0,0,0)
v.setAlignment(Qt.AlignTop)
w.setLayout(v)
w.setStyleSheet("background:blue")
i = self.tabs.addTab(w,label)
self.tabs.setCurrentIndex(i)
def open_newTab(self,i):
if i==-1:
self.add_new_tab()
import sys
app = QApplication(sys.argv)
window = mainwindow()
window.show()
sys.exit(app.exec_())
As you can see in the above both pictures toolbar is present.
But when I go to the previous tab the toolbar disappear as shown in below image.
In my QMainWindow i have a button which opens a new QDialog in the bottom right monitorcorner with a successmessage when i click it.
Now, if i move the QMainWindow to another monitor (i have 3 monitor) and click the button the successmessage popup appears in the monitor where the QMainWindow was opened. What i want is that the popup message appears in the monitor where my QMainWindow actually is. So if i move the QMainWindow to Monitor 1 and click the button, the successpopup should opens in monitor 1. If the QMainWindow is in monitor 2, the successpopup should open in monitor 2 an same for monitor 3.
with
screenNumber = QDesktopWidget().screenNumber(self)
i can read the screennumber where the mainwindow is. and this works fine. Evertime i click the button i read out the screennumber. But i don't found a way, to set the screennumber to my notification.
Any ideas?
Edit:
maybe it helps if i show my notify class
notes.py
from UIs.UI_notify import Ui_Notification
from PyQt5.QtWidgets import QDialog, QApplication, QDesktopWidget
from PyQt5 import QtCore
from PyQt5.QtCore import QRect, QPropertyAnimation, QTimer
import sys
class icon():
checked = "check-circle"
alert = "times-circle"
question = "question-circle"
class notify(QDialog, Ui_Notification):
def __init__(self, parent=None):
super(notify,self).__init__(parent)
self.setupUi(self)
self.setWindowFlag(QtCore.Qt.WindowType.FramelessWindowHint)
self.setAttribute(QtCore.Qt.WidgetAttribute.WA_TranslucentBackground)
## Some helping stuff
############################################################
parent_sSize = QDesktopWidget().screenGeometry(parent)
parent_screenNumber = QDesktopWidget().screenNumber(parent)
sSize = QDesktopWidget().screenGeometry()
screenNumber = QDesktopWidget().screenNumber()
print("notification ScreenNumber = " + str(screenNumber))
print(sSize.width())
print(sSize.height())
print("Parents ScreenNumber = " + str(parent_screenNumber))
print(parent_sSize.width())
print(parent_sSize.height())
self.Note_Exit.clicked.connect(self.close)
## ScreenSize from parent
############################################################
self.hidedPos = QRect(parent_sSize.width()-self.width()-10,
parent_sSize.height()-self.height()+200,
self.frameGeometry().width(),
self.frameGeometry().height())
self.showPos = QRect(parent_sSize.width()-self.width()-10,
parent_sSize.height()-self.height()-50,
self.frameGeometry().width(),
self.frameGeometry().height())
def setNote(self, icon=icon.checked, headline="Headline", text="Text"):
self.icon = icon
self.headline = headline
self.text = text
self.noty_Label_Icon.setText(self.icon)
self.noty_Label_Headline.setText(self.headline)
self.noty_Label_Text.setText(self.text)
self.setGeometry(self.hidedPos)
self.anim = QPropertyAnimation(self,b"geometry")
self.anim.setDuration(700)
self.anim.setEasingCurve(QtCore.QEasingCurve.OutBack)
self.anim.setEndValue(self.showPos)
self.anim.start()
self.notyTimer = QTimer()
self.notyTimer.singleShot(4000,self.hideNote)
def hideNote(self):
self.anim = QPropertyAnimation(self,b"geometry")
self.anim.setDuration(700)
self.anim.setEasingCurve(QtCore.QEasingCurve.InOutBack)
self.anim.setEndValue(self.hidedPos)
self.anim.start()
self.anim.finished.connect(self.close)
if __name__ == "__main__":
notes = QApplication(sys.argv)
dialog = notify()
dialog.show()
sys.exit(notes.exec())
You cannot use the size of the widget during its construction, as at that moment it has a default size (640x480 for top level widgets, 100x30 for widgets created with a parent, including dialogs): the only reliable option is to use the sizeHint() or ensure that the layout has been properly activated with adjustSize().
Then, you don't need the screen to get the target position, as the parent geometry will suffice, but you do need it for the start position, otherwise the dialog will "pop up" at an arbitrary point below the window. Note that QDesktopWidget is considered obsolete, and you should use QScreen instead.
Finally, since you might want to reuse the notification, the start position should be set when the popup is actually being shown, not before. The same goes for the position when hiding (in case the notification could be moved).
class Notify(QDialog, Ui_Notification):
def __init__(self, parent):
super().__init__(parent)
self.setupUi(self)
self.setWindowFlag(QtCore.Qt.WindowType.FramelessWindowHint)
self.setAttribute(QtCore.Qt.WA_TranslucentBackground)
self.showAnim = QPropertyAnimation(self, b'geometry')
self.showAnim.setDuration(700)
self.showAnim.setEasingCurve(QtCore.QEasingCurve.OutBack)
self.hideAnim = QPropertyAnimation(self, b'geometry')
self.hideAnim.setDuration(700)
self.hideAnim.setEasingCurve(QtCore.QEasingCurve.InOutBack)
self.hideTimer = QTimer(self, singleShot=True)
self.hideTimer.setInterval(4000)
self.hideTimer.timeout.connect(self.hideNote)
self.showAnim.finished.connect(self.hideTimer.start)
self.hideAnim.finished.connect(self.close)
def setNote(self, icon=icon.checked, headline="Headline", text="Text"):
self.icon = icon
self.headline = headline
self.text = text
self.noty_Label_Icon.setText(self.icon)
self.noty_Label_Headline.setText(self.headline)
self.noty_Label_Text.setText(self.text)
self.adjustSize() # important!
endRect = self.rect()
center = self.parent().geometry().center()
endRect.moveCenter(center)
screen = QApplication.screenAt(center)
startRect = QRect(endRect)
startRect.moveTop(screen.geometry().bottom())
self.setGeometry(startRect)
self.showAnim.setStartValue(startRect)
self.showAnim.setEndValue(endRect)
self.showAnim.start()
self.show()
def hideNote(self):
rect = self.geometry()
self.hideAnim.setStartValue(rect)
screen = QApplication.screenAt(rect.center())
rect.moveTop(screen.geometry().bottom())
self.hideAnim.setEndValue(rect)
self.hideAnim.start()
if __name__ == "__main__":
notes = QApplication(sys.argv)
notes.setStyle('fusion')
w = QMainWindow()
b = QPushButton('click!')
w.setCentralWidget(b)
w.show()
notify = Notify(w)
b.clicked.connect(lambda: notify.setNote())
sys.exit(notes.exec())
Be aware that if you're going to create the popup every time, you should also set the WA_DeleteOnClose attribute in order to destroy it when closed, otherwise it will be kept in memory.
Note: QTimer.singleShot() is a static function, creating an instance of QTimer to use it is pointless, as that instance won't be used and a new QTimer would be created anyway.
Thank you.
In the meantime i found a solution which works for me.
Look a little dirty but works.
could you tell me, whats the difference between my code an yours?
Why should i use your code, except the fact that you are a better programmer ;-)
I set the WA_DeleteOnClose Attribute.
Good to know that. Thanks
notes.py
from UIs.UI_notify import Ui_Notification
from PyQt5.QtWidgets import QDialog, QApplication
from PyQt5 import QtCore
from PyQt5.QtCore import QRect, QPropertyAnimation, QTimer
import sys
class icon():
checked = "check-circle"
alert = "times-circle"
question = "question-circle"
clock = "clock"
class notify(QDialog, Ui_Notification):
def __init__(self, parent=None):
super(notify,self).__init__(parent)
self.setupUi(self)
self.setWindowFlag(QtCore.Qt.WindowType.FramelessWindowHint)
self.setAttribute(QtCore.Qt.WidgetAttribute.WA_TranslucentBackground)
self.setAttribute(QtCore.Qt.WidgetAttribute.WA_DeleteOnClose)
self.setWindowModality(QtCore.Qt.NonModal)
self.Note_Exit.clicked.connect(self.close)
self.parent_h = self.parent().geometry().height()
self.parent_w = self.parent().geometry().width()
self.parent_x = self.parent().geometry().x()
self.parent_y = self.parent().geometry().y()
self.dialog_w = self.width()
self.dialog_h = self.height()
self.setGeometry(self.parent_x+self.parent_w-self.dialog_w-10, self.parent_y+self.parent_h-self.dialog_h+120, self.dialog_w, self.dialog_h)
## ScreenSize from parent
############################################################
def setNote(self, icon=icon.checked, headline="Headline", text="Text"):
self.icon = icon
self.headline = headline
self.text = text
self.noty_Label_Icon.setText(self.icon)
self.noty_Label_Headline.setText(self.headline)
self.noty_Label_Text.setText(self.text)
self.anim = QPropertyAnimation(self,b"geometry")
self.anim.setDuration(700)
self.anim.setEasingCurve(QtCore.QEasingCurve.OutBack)
self.anim.setEndValue(QRect(self.parent_x+self.parent_w-self.dialog_w-10, self.parent_y+self.parent_h-self.dialog_h-20, self.dialog_w, self.dialog_h))
self.anim.start()
self.notyTimer = QTimer()
self.notyTimer.singleShot(4000,self.hideNote)
def hideNote(self):
self.anim = QPropertyAnimation(self,b"geometry")
self.anim.setDuration(700)
self.anim.setEasingCurve(QtCore.QEasingCurve.InOutBack)
self.anim.setEndValue(QRect(self.parent_x+self.parent_w-self.dialog_w-10, self.parent_y+self.parent_h-self.dialog_h+120, self.dialog_w, self.dialog_h))
self.anim.start()
self.anim.finished.connect(self.close)
if __name__ == "__main__":
notes = QApplication(sys.argv)
dialog = notify()
dialog.show()
sys.exit(notes.exec())
I want to add buttons to the tabs in the QTabWidget.
My first instinct was to try to get the position of each tab and then add the button ontop of the tab, but I cant figure out how to get the position of the tab! Only the entire tab widget.
I was looking around and now what I think I should do is make a custom TabBar class where I can place buttons on each tab like the standard Qt close button.
Anyone here who can send me in the right direction?
Okay so I found out how to make it work like I want it. It was actually quite simple, I made a QWidget class with a horizontal layout and two buttons and passed it to the setTabButton function. For anyone interested see the code below.
import sys
from PyQt5 import QtWidgets
from PyQt5.QtWidgets import QApplication, QMainWindow
class TabExample(QMainWindow):
def __init__(self):
super(TabExample, self).__init__()
self.setWindowTitle("Tab example")
# Create widgets
self.tab_widget = QtWidgets.QTabWidget()
self.setCentralWidget(self.tab_widget)
# Label's to fill widget
self.label1 = QtWidgets.QLabel("Tab 1")
self.label2 = QtWidgets.QLabel("Tab 2")
# Adding tab's
self.tab_widget.addTab(self.label1, "Tab 1")
self.tab_widget.addTab(self.label2, "Tab 2")
# Tab button's
self.right = self.tab_widget.tabBar().RightSide
self.tab_widget.tabBar().setTabButton(0, self.right, TabButtonWidget())
self.tab_widget.tabBar().setTabButton(1, self.right, TabButtonWidget())
# Tab settings
self.tab_widget.tabBar().setMovable(True)
self.show()
class TabButtonWidget(QtWidgets.QWidget):
def __init__(self):
super(TabButtonWidget, self).__init__()
# Create button's
self.button_add = QtWidgets.QPushButton("+")
self.button_remove = QtWidgets.QPushButton("-")
# Set button size
self.button_add.setFixedSize(16, 16)
self.button_remove.setFixedSize(16, 16)
# Create layout
self.layout = QtWidgets.QVBoxLayout()
self.layout.setSpacing(0)
self.layout.setContentsMargins(0, 0, 0, 0)
# Add button's to layout
self.layout.addWidget(self.button_add)
self.layout.addWidget(self.button_remove)
# Use layout in widget
self.setLayout(self.layout)
if __name__ == "__main__":
app = QApplication(sys.argv)
gui = TabExample()
sys.exit(app.exec_())
I am currently trying to display a split screen view onto my window using PyQt5 with QSplitter and QMainWindow. I need QMainWindow to be able to create the menu options for the application that I am working on and would need to use QSplitter to use three separate windows for the application. Currently based on my code, the window is showing up, but there is no split screen shown at all. The only thing on the display is a blank screen when there should be the numbers: 1, 2, 3, and 4 shown in each corner.
I have tried to implement the QSplitters into the main window but then found that that approach does not work as it cannot set the layout of the QSplitters on top of setting the layout of the main window from QMainWindow. The next approach I used was the class based model where I defined what exactly I wanted for each splitter and implemented the subwindows into the main window and used two splitters (horizontal and vertical).
import sys
#imports
from PyQt5.QtWidgets import QApplication, QWidget, QMainWindow, QAction, QVBoxLayout, QStackedWidget
from PyQt5.QtWidgets import QMessageBox, QFrame, QSplitter, QTextEdit, QHBoxLayout, QLineEdit, QLabel
from PyQt5.QtGui import QKeySequence
from PyQt5.QtGui import *
from PyQt5.QtCore import *
from PyQt5.QtGui import QIcon #to import icon
'''
class widget1(QWidget):
"""docstring for widget1"""
def __init__(self):
QWidget.__init__(self)
hbox = QHBoxLayout()
#create split screen
#this is the top left frame of the window
topleft = QFrame()
topleft.setFrameShape(QFrame.StyledPanel)
#first splitter
splitter1 = QSplitter(Qt.Horizontal)
lineedit = QLineEdit()
splitter1.addWidget(topleft)
splitter1.addWidget(lineedit)
splitter1.setSizes([200,200])
#second splitter and it is located at the bottom of the screen
bottom = QFrame()
bottom.setFrameShape(QFrame.StyledPanel)
splitter2 = QSplitter(Qt.Horizontal)
#add the splitter to the layout
hbox.addWidget(splitter2)
'''
class SubWindow(QWidget):
def __init__(self, label):
super(SubWindow, self).__init__()
self.label = QLabel(label)
self.label.setAlignment(Qt.AlignCenter)
self.label.setStyleSheet("QLabel {font-size:40px;}")
self.main_layout = QVBoxLayout()
self.main_layout.addWidget(self.label)
self.setLayout(self.main_layout)
#GUI class to create window
class GUI(QMainWindow):
"""docstring for GUI"""
def __init__(self,):
# Understand and explain ...
super().__init__()
#initialize the UI using the initUI method
self.initUI()
def initUI(self):
#set the title of the window
self.setWindowTitle('Visualization')
#Set the status bar in the beginning
self.statusBar().showMessage("In Progress")
#create new menubar object at top of window
menubar = self.menuBar()
#add file button to menubar
file_menu = menubar.addMenu("File")
#add edit button to menubar
edit_menu = menubar.addMenu("Edit")
#add view button to menubar
view_menu = menubar.addMenu("View")
#path for new icon and create the icon
new_icon = QIcon('newfileicon.png')
open_icon =QIcon('openfileicon.png')
exitapp_icon = QIcon('exitappicon.png')
#create new subbutton for the file menu and add icon and shortcuts
#as well as connecting the methods for each file menu
new_action = QAction(new_icon,'New', self)
new_action.setShortcut('Ctrl+N')
new_action.triggered.connect(self.newCall)
open_action = QAction(open_icon,'Open', self)
open_action.setShortcut('Ctrl+O')
open_action.triggered.connect(self.openCall)
exit_action = QAction(exitapp_icon,'Exit', self)
exit_action.setShortcut('Ctrl+X')
exit_action.triggered.connect(self.exitCall)
#add the action to the file menu button
file_menu.addAction(new_action)
file_menu.addAction(open_action)
file_menu.addAction(exit_action)
#when hovering over the "new", "open", and "exit", update statusbar
new_action.setStatusTip("Create New File")
open_action.setStatusTip("Open a file")
exit_action.setStatusTip("Exit application")
#when clicking the exit, close the application
exit_action.triggered.connect(self.close)
self.SubWindow1 = SubWindow("1")
self.SubWindow2 = SubWindow("2")
self.SubWindow3 = SubWindow("3")
self.SubWindow4 = SubWindow("4")
self.subsplitter1 = QSplitter(Qt.Horizontal)
self.subsplitter1.addWidget(self.SubWindow1)
self.subsplitter1.addWidget(self.SubWindow2)
self.subsplitter2 = QSplitter(Qt.Horizontal)
self.subsplitter2.addWidget(self.SubWindow3)
self.subsplitter2.addWidget(self.SubWindow4)
self.subsplitter = QSplitter(Qt.Vertical)
self.subsplitter.addWidget(self.subsplitter1)
self.subsplitter.addWidget(self.subsplitter2)
self.main_layout = QVBoxLayout()
self.main_layout.addWidget(self.subsplitter)
self.setLayout(self.main_layout)
#hbox = widget1()
#self.view = QHBoxLayout(self)
#resize the window to a 900x800 window
self.resize(900, 800)
def newCall(self):
QMessageBox.about(self, "Confirmation", "Are you sure you want to create a new file?")
def openCall(self):
QMessageBox.about(self, "Confirmation", "Are you sure you want to open a file?")
#if yes to the messagebox, then close, else dont close and pass
def exitCall(self):
reply = QMessageBox.question(self, "Confirmation", "Are you sure you want to exit the application?",
QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
if reply == QMessageBox.Yes:
self.close
sys.exit()
else:
pass
#main function
if __name__ == '__main__':
app = QApplication(sys.argv)
gui = GUI()
gui.show()
sys.exit(app.exec_())
I expected there to be the results of having four split screens with the values of "1", "2", "3", and "4" on each corner of the screen. Instead the output is what I have gotten before which is just a blank screen with the menubar and status bar being functional.
QMainWindow unlike QWidget already has a predefined layout:
So you should not use a layout to set the QSplitter but use the setCentralWidget() method of QMainWindow:
# ...
self.subsplitter = QSplitter(Qt.Vertical)
self.subsplitter.addWidget(self.subsplitter1)
self.subsplitter.addWidget(self.subsplitter2)
self.setCentralWidget(self.subsplitter)
self.resize(900, 800)
# ...
I never tried creating a GUI with a language other than Java(kinda left it aside not long ago)
and started using Python.
made a simple program that calculates Pi to a certain digit as the user wishes.
Now, I created a window with PyQt4, made a button and got everything in place.
How can I add a input box so that the user could enter a number into it, make the button "Enter" the information and at the end of all that output it to the window instead of the terminal?
That's what I've got for now:
import sys
from PyQt4 import QtGui
from PyQt4 import QtCore
from decimal import *
class Window(QtGui.QMainWindow):
def __init__(self):
super(Window, self).__init__()
self.setGeometry(50, 50, 800, 600)
self.setWindowTitle("Pi's Nth Digit")
self.setWindowIcon(QtGui.QIcon('icon.jpg'))
self.buttons()
def buttons(self):
btn = QtGui.QPushButton("Quit",self)
btn1 = QtGui.QPushButton("Get Pi",self)
btn.clicked.connect(QtCore.QCoreApplication.instance().quit)
btn1.clicked.connect(self.getpi())
btn1.resize(btn1.sizeHint())
btn.resize(btn.sizeHint())
btn1.move(350,500)
btn.move(450,500)
self.show()
def start():
app = QtGui.QApplication(sys.argv)
GUI = Window()
sys.exit(app.exec_())
start()
don't mind the getpi function.
Thanks! :)
You would want to use a QLineEdit or a QSpinBox for a number. If you want multiple things in a widget you would use a layout. A QMainWindow typically has one central widget and toolbars and dock widgets.
class Window(QtGui.QMainWindow):
def __init__(self):
super().__init__()
self.container = QtGui.QWidget()
self.setCentralWidget(self.container)
self.container_lay = QtGui.QVBoxLayout()
self.container.setLayout(self.container_lay)
# Input
self.le = QtGui.QLineEdit()
self.container_lay.addWidget(self.le)
# enter button
self.enter_btn = QtGui.QPushButton("Enter")
self.container_lay.addWidget(self.enter_btn)
self.enter_btn.clicked.connect(self.run) # No '()' on run you want to reference the method.
# display
self.container_lay.addWidget(QtGui.QLabel("Answer:"))
self.ans = QtGui.QLabel()
self.container_lay.addWidget(self.ans)
def run(self):
precision = self.le.text()
pi = str(round(math.pi, precision)) # probably different formatting
self.ans.setText(pi)
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
window = Window()
window.show()
sys.exit(app.exec_())
You have almost everything, just add a QLineEdit to get the input and a QLabel where to show the result (with QLabel.setText).