Python 3.5, pyqt5 progress bar gui in seperate window - python-3.x

I am new to PyQt5 and pretty new to Python. I am trying to create a graphical user interface using PyQt5 in Python 3.5, where I click a button to launch a separate window in which the progress bar iterates up to 100 and then closing the window at the end of iteration to generate a message "it worked".
The problem is the progress bar is created but doesn't update and after reaching the end it doesn't display the message that it worked. When I try to debug it crashes completely with no warning as to why. I don't know how else to debug the code
My progress bar code is shown below:
from PyQt5 import QtCore, QtWidgets
import sys
class Ui_Form(object):
def setupUi(self, Form):
Form.setObjectName("Form")
Form.resize(1075, 84)
self.progressBar = QtWidgets.QProgressBar(Form)
self.progressBar.setGeometry(QtCore.QRect(30, 30, 1000, 35))
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.progressBar.sizePolicy().hasHeightForWidth())
self.progressBar.setSizePolicy(sizePolicy)
self.progressBar.setMinimumSize(QtCore.QSize(1000, 35))
self.progressBar.setMaximumSize(QtCore.QSize(1000, 35))
self.progressBar.setProperty("value", 0)
self.progressBar.setObjectName("progressBar")
self.retranslateUi(Form)
QtCore.QMetaObject.connectSlotsByName(Form)
def setValue(self, val):
self.progressBar.setProperty("value", val)
def retranslateUi(self, Form):
_translate = QtCore.QCoreApplication.translate
Form.setWindowTitle(_translate("Form", "Progress bar"))
The main program is given below
from PyQt5.QtWidgets import QApplication, QDialog, QWidget, QPushButton, QMessageBox
import ProgressBar
import sys
class App(QWidget):
def __init__(self):
super().__init__()
self.title = 'PyQt5 button - pythonspot.com'
self.left = 200
self.top = 200
self.width = 320
self.height = 200
self.initUI()
def initUI(self):
self.setWindowTitle(self.title)
self.setGeometry(self.left, self.top, self.width, self.height)
button = QPushButton('PyQt5 button', self)
button.setToolTip('This is an example button')
button.move(100, 70)
button.clicked.connect(self.on_click)
self.show()
def on_click(self):
print('PyQt5 button click')
app1 = QApplication(sys.argv)
window = QDialog()
ui = ProgressBar.Ui_Form()
ui.setupUi(window)
window.show()
for i in range(0, 100):
ui.setValue(((i + 1) / 100) * 100)
app1.quit()
QMessageBox.information(self, "Message", "Data Loaded")
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = App()
sys.exit(app.exec_())
Any help would be greatly appreciated.

Here is my final code. I have tried to include some good practices with using pyqt designer and not editing the created file directly but run it from another file and call into it. This has made things much easier when I wanted to change things as suggested. I have also included a time.sleep(0.1) to the code to slow it down so you can see it working. Hope it helps.
ProgressBar_ui.py - file generated by converted in python from ProgressBar.ui
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'Base.ui'
#
# Created by: PyQt5 UI code generator 5.6
#
# WARNING! All changes made in this file will be lost!
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_Form(object):
def setupUi(self, Form):
Form.setObjectName("Form")
Form.resize(1075, 84)
self.progressBar = QtWidgets.QProgressBar(Form)
self.progressBar.setGeometry(QtCore.QRect(30, 30, 1000, 35))
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.progressBar.sizePolicy().hasHeightForWidth())
self.progressBar.setSizePolicy(sizePolicy)
self.progressBar.setMinimumSize(QtCore.QSize(1000, 35))
self.progressBar.setMaximumSize(QtCore.QSize(1000, 35))
self.progressBar.setProperty("value", 0)
self.progressBar.setObjectName("progressBar")
self.retranslateUi(Form)
QtCore.QMetaObject.connectSlotsByName(Form)
def retranslateUi(self, Form):
_translate = QtCore.QCoreApplication.translate
Form.setWindowTitle(_translate("Form", "Progress bar"))
ProgressBar.py - Calls ProgrssBar.ui
from PyQt5 import QtCore, QtGui, QtWidgets
import sys
from ProgressBar_ui import Ui_Form
class ProgressBar(QtWidgets.QDialog, Ui_Form):
def __init__(self, desc = None, parent=None):
super(ProgressBar, self).__init__(parent)
self.setupUi(self)
self.show()
if desc != None:
self.setDescription(desc)
def setValue(self, val): # Sets value
self.progressBar.setProperty("value", val)
def setDescription(self, desc): # Sets Pbar window title
self.setWindowTitle(desc)
def main():
app = QtWidgets.QApplication(sys.argv) # A new instance of QApplication
form = ProgressBar('pbar') # We set the form to be our MainWindow (design)
app.exec_() # and execute the app
if __name__ == '__main__': # if we're running file directly and not importing it
main() # run the main function
Main_program.py - Run from here
from PyQt5.QtWidgets import QApplication, QWidget, QPushButton, QMessageBox
from ProgressBar import ProgressBar
import sys, time
class App(QWidget):
def __init__(self):
super().__init__()
self.title = 'PyQt5 button - pythonspot.com'
self.left = 200
self.top = 200
self.width = 320
self.height = 200
self.initUI()
def initUI(self):
self.setWindowTitle(self.title)
self.setGeometry(self.left, self.top, self.width, self.height)
button = QPushButton('PyQt5 button', self)
button.setToolTip('This is an example button')
button.move(100, 70)
button.clicked.connect(self.on_click)
self.show()
def on_click(self):
pb = ProgressBar()
for i in range(0, 100):
time.sleep(0.05)
pb.setValue(((i + 1) / 100) * 100)
QApplication.processEvents()
pb.close()
QMessageBox.information(self, "Message", "Data Loaded")
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = App()
sys.exit(app.exec_())

Figured out solution eventually. 3 problems:
1) Should only call QApplication once in the main application an not again
2) Add QApplication.processEvents() to the forloop so it updates the progressbar continuously
3) Add window.close() after the forloop so it closes

Related

How to use QtWebEngine createWindow in PyQt5

I am trying to make a window that contains a QWebEngineView. Now I want the browser to be able to handle the create window or _blank type triggers, or specifically to open a URL in a new window when required. In the below code, when there is requirement to create a window by the browser, createwindow() is called, but that doesn't open the window. Please help me with the correct way to open a new window by the browser when required in the below case.
import json
import sys
import os
import time
import json
import sys
import platform
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtWebEngineWidgets import QWebEngineView, QWebEnginePage
from PyQt5.QtWebEngineWidgets import QWebEngineSettings as QWebSettings
from PyQt5.QtGui import QDesktopServices
from PyQt5.QtCore import QUrl
from main_dash import Ui_MainWindow
class MainDashWindow(QMainWindow):
socketSignal = QtCore.pyqtSignal(object) # must be defined in class level
def __init__(self):
QMainWindow.__init__(self)
self.ui = Ui_MainWindow()
# self.ui.setupUi(self)
# ui = Ui_MainWindow()
self.isMax = 0
self.ui.setupUi(self)
def re_setup(self):
self.page = WebEnginePage2()
self.page.Notifications = True
self.ui.full_content_container.hide()
self.page.createWindow = True
self.page.settings().setAttribute(QWebSettings.JavascriptEnabled, True)
self.page.settings().setAttribute(QWebSettings.JavascriptCanOpenWindows, True)
self.page.settings().setAttribute(
QWebSettings.JavascriptCanAccessClipboard, True)
# self.full_content_container is the webengineview in the mainUi file
self.ui.full_content_container.setPage(self.page)
# self.ui.full_content_container.setContextMenuPolicy(Qt.NoContextMenu)
url6 = "...../icons_nec/ui/index.html"
self.ui.full_content_container.setUrl(QtCore.QUrl(url6))
self.ui.full_content_container.loadFinished.connect(
self.on_load_finished)
########################################################################
self.show()
## ==> END ##
def get_path(self, filename):
if hasattr(sys, "_MEIPASS"):
return f'{os.path.join(sys._MEIPASS, filename)}'
else:
return f'{filename}'
def on_load_finished(self):
self.ui.full_content_container.show()
class WebEnginePage2(QWebEnginePage):
def __init__(self, *args, **kwargs):
QWebEnginePage.__init__(self, *args, **kwargs)
self.featurePermissionRequested.connect(
self.onFeaturePermissionRequested)
def onFeaturePermissionRequested(self, url, feature):
self.setFeaturePermission(
url, feature, QWebEnginePage.PermissionGrantedByUser)
def createWindow(self,
wintype: QWebEnginePage.WebWindowType) -> QWebEngineView:
"""Called by Qt when a page wants to create a new tab or window.
In case the user wants to open a resource in a new tab, we use the
createWindow handling of the main page to achieve that.
See WebEngineView.createWindow for details.
"""
return self.page().inspectedPage().view().createWindow(wintype)
# Store external windows.
external_windows = []
def acceptNavigationRequest(self, url, _type, isMainFrame):
print("in navigation")
if _type == QWebEnginePage.NavigationTypeLinkClicked:
w = QWebEngineView()
w.setUrl(url)
w.show()
print("link detected")
# Keep reference to external window, so it isn't cleared up.
self.external_windows.append(w)
return False
# QDesktopServices.openUrl(url)
# elif _type == QWebEnginePage.NavigationType
return super().acceptNavigationRequest(url, _type, isMainFrame)
if __name__ == "__main__":
app = QApplication(sys.argv)
window = MainDashWindow()
window.re_setup()
sys.exit(app.exec_())
Here is the Ui_MainWindow file, which is being imported above.
I need to figure out with such a scenario how can I implement createWindow() if required by websites.
from PyQt5 import QtWebEngineWidgets
import all_icons_rc
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(1280, 720)
MainWindow.setMinimumSize(QtCore.QSize(1280, 720))
MainWindow.setMaximumSize(QtCore.QSize(1920, 1080))
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.centralwidget)
self.verticalLayout_2.setContentsMargins(0, 0, 0, 0)
self.verticalLayout_2.setSpacing(0)
self.verticalLayout_2.setObjectName("verticalLayout_2")
self.Header = QtWidgets.QFrame(self.centralwidget)
self.Header.setMinimumSize(QtCore.QSize(0, 40))
self.Header.setMaximumSize(QtCore.QSize(16777215, 50))
self.Header.setStyleSheet("background-color: rgb(33, 37, 41);")
self.Header.setFrameShape(QtWidgets.QFrame.NoFrame)
self.Header.setFrameShadow(QtWidgets.QFrame.Raised)
self.Header.setObjectName("Header")
self.horizontalLayout_4 = QtWidgets.QHBoxLayout(self.Header)
self.horizontalLayout_4.setContentsMargins(0, 0, 0, 0)
self.horizontalLayout_4.setSpacing(0)
self.horizontalLayout_4.setObjectName("horizontalLayout_4")
self.frame_2 = QtWidgets.QFrame(self.Header)
self.frame_2.setStyleSheet("")
self.frame_2.setFrameShape(QtWidgets.QFrame.StyledPanel)
self.frame_2.setFrameShadow(QtWidgets.QFrame.Raised)
self.frame_2.setObjectName("frame_2")
self.horizontalLayout_4.addWidget(self.frame_2)
self.frame = QtWidgets.QFrame(self.Header)
self.frame.setMaximumSize(QtCore.QSize(150, 16777215))
self.frame.setStyleSheet("/*background-color: rgb(85, 255, 0);*/")
self.frame.setFrameShape(QtWidgets.QFrame.StyledPanel)
self.frame.setFrameShadow(QtWidgets.QFrame.Raised)
self.frame.setObjectName("frame")
self.horizontalLayout = QtWidgets.QHBoxLayout(self.frame)
self.horizontalLayout.setSpacing(15)
self.horizontalLayout.setObjectName("horizontalLayout")
self.minimize_btn = QtWidgets.QPushButton(self.frame)
self.minimize_btn.setText("")
icon = QtGui.QIcon()
icon.addPixmap(QtGui.QPixmap(
":/icons/Icons/icons8_macos_minimize_50px.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.minimize_btn.setIcon(icon)
self.minimize_btn.setIconSize(QtCore.QSize(30, 30))
self.minimize_btn.setFlat(True)
self.minimize_btn.setObjectName("minimize_btn")
self.horizontalLayout.addWidget(self.minimize_btn)
self.maximize_btn = QtWidgets.QPushButton(self.frame)
self.maximize_btn.setText("")
icon1 = QtGui.QIcon()
icon1.addPixmap(QtGui.QPixmap(
":/icons/Icons/icons8_maximize_window_50px.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.maximize_btn.setIcon(icon1)
self.maximize_btn.setIconSize(QtCore.QSize(30, 30))
self.maximize_btn.setFlat(True)
self.maximize_btn.setObjectName("maximize_btn")
self.horizontalLayout.addWidget(self.maximize_btn)
self.close_btn = QtWidgets.QPushButton(self.frame)
self.close_btn.setText("")
icon2 = QtGui.QIcon()
icon2.addPixmap(QtGui.QPixmap(
":/icons/Icons/icons8_Close_50px_2.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.close_btn.setIcon(icon2)
self.close_btn.setIconSize(QtCore.QSize(30, 30))
self.close_btn.setFlat(True)
self.close_btn.setObjectName("close_btn")
self.horizontalLayout.addWidget(self.close_btn)
self.horizontalLayout_4.addWidget(self.frame)
self.verticalLayout_2.addWidget(self.Header)
self.body = QtWidgets.QFrame(self.centralwidget)
self.body.setFrameShape(QtWidgets.QFrame.StyledPanel)
self.body.setFrameShadow(QtWidgets.QFrame.Raised)
self.body.setLineWidth(0)
self.body.setObjectName("body")
self.verticalLayout_3 = QtWidgets.QVBoxLayout(self.body)
self.verticalLayout_3.setContentsMargins(0, 0, 0, 0)
self.verticalLayout_3.setSpacing(0)
self.verticalLayout_3.setObjectName("verticalLayout_3")
self.full_content_container = QtWebEngineWidgets.QWebEngineView(
self.body)#<----This is webengineview
self.full_content_container.setStyleSheet("background-color: rgb(85, 255, 255);\n"
"border:none;")
self.full_content_container.setObjectName("full_content_container")
self.verticalLayout_3.addWidget(self.full_content_container)
self.verticalLayout_2.addWidget(self.body)
MainWindow.setCentralWidget(self.centralwidget)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
For now, just Ignore the icons.
index.html file snippet which is being loaded in webengineview for testing
<!DOCTYPE html>
<html>
<body>
<h1>The a target attribute</h1>
<p>Open link in a new window or tab: Visit PathOr!</p>
</body>
</html>
UPDATE:
Below is an implementaion based on your example code. Everything should work as expected if you completely replace your WebEnginePage2 class with this one:
class WebEnginePage2(QWebEnginePage):
_windows = {}
#classmethod
def newWindow(cls):
window = QWebEngineView()
window.setObjectName(f'window-{id(window)}')
window.setAttribute(QtCore.Qt.WA_DeleteOnClose, True)
window.destroyed.connect(
lambda window: cls._windows.pop(window.objectName(), None))
window.setPage(cls(window))
cls._windows[window.objectName()] = window
return window
def __init__(self, *args, **kwargs):
QWebEnginePage.__init__(self, *args, **kwargs)
self.featurePermissionRequested.connect(
self.onFeaturePermissionRequested)
self.geometryChangeRequested.connect(self.handleGeometryChange)
def handleGeometryChange(self, rect):
view = self.view()
window = QtGui.QWindow.fromWinId(view.winId())
if window is not None:
rect = rect.marginsRemoved(window.frameMargins())
view.resize(rect.size())
view.show()
def createWindow(self, mode):
window = self.newWindow()
if mode != QtWebEngineWidgets.QWebEnginePage.WebDialog:
window.resize(800, 600)
window.show()
return window.page()
def onFeaturePermissionRequested(self, url, feature):
self.setFeaturePermission(
url, feature, QWebEnginePage.PermissionGrantedByUser)
You need to create a new instance of the browser window and keep a reference to it in a window list. It's also important to ensure the window is given an appropriate size, otherwise it won't be visible. For windows opened with javascript, the geometryChangeRequested signal can be used to set the requested size, otherwise a default should be used.
Below is a simple demo that implements the basic features. Hopefully it should be obvious how to adapt this to your own application:
from PyQt5 import QtCore, QtGui, QtWidgets, QtWebEngineWidgets
class Browser(QtWebEngineWidgets.QWebEngineView):
_windows = set()
#classmethod
def _removeWindow(cls, window):
cls._windows.discard(window)
#classmethod
def newWindow(cls):
window = cls()
cls._windows.add(window)
return window
def __init__(self, parent=None):
super().__init__(parent)
self.setAttribute(QtCore.Qt.WA_DeleteOnClose, True)
self.page().geometryChangeRequested.connect(self.handleGeometryChange)
self.page().titleChanged.connect(self.setWindowTitle)
def closeEvent(self, event):
self._removeWindow(self)
event.accept()
def handleGeometryChange(self, rect):
window = QtGui.QWindow.fromWinId(self.winId())
if window is not None:
rect = rect.marginsRemoved(window.frameMargins())
self.resize(rect.size())
self.setFocus()
self.show()
def createWindow(self, mode):
window = self.newWindow()
if mode != QtWebEngineWidgets.QWebEnginePage.WebDialog:
window.resize(800, 600)
window.show()
return window
html = """
<html><head><title>Test Page</title>
<script type="text/javascript"><!--
var count = 0
var url = 'https://www.google.com'
function newWindow() {
count += 1
window.open(url, 'Test' + count, 'width=640,height=480');
}
--></script>
</head>
<body>
<input type="button" value="New Window" onclick="newWindow()" />
<p>Blank</p>
</body>
</html>"""
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
browser = Browser()
browser.setHtml(html)
browser.setGeometry(600, 100, 400, 200)
browser.show()
sys.exit(app.exec_())

Python PyQt5 Terminal Command execution problem on a button click

I'm trying to create an application, that can execute an embedded Terminal command when ever the button is clicked. The actual problem occurs when i click the button and nothing happens.
I have two scripts one has a terminal widget and the other has the main GUI. Any Help, would be highly appreciated.
That's first Script
import sys
from PyQt5 import QtCore, QtWidgets
class EmbTerminal(QtWidgets.QWidget):
def __init__(self, parent=None):
super(EmbTerminal, self).__init__(parent)
self._process = []
self.start_process('urxvt',['-embed', str(int(self.winId())),"-e","tmux"])
def start_process(self,prog,options):
child = QtCore.QProcess(self)
self._process.append(child)
child.start(prog,options)
def run_command(self, command = "ls" ):
program = "tmux"
options = []
options.extend(["send-keys"])
options.extend([command])
options.extend(["Enter"])
self.start_process(program, options)
That's Second Script
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_Dialog(object):
def setupUi(self, Dialog):
Dialog.setObjectName("Dialog")
Dialog.resize(745, 496)
self.tabWidget = QtWidgets.QTabWidget(Dialog)
self.tabWidget.setGeometry(QtCore.QRect(100, 190, 561, 261))
self.tabWidget.setObjectName("tabWidget")
self.tab = QtWidgets.QWidget()
self.tab.setObjectName("tab")
self.tabWidget.addTab(EmbTerminal(), "Terminal")
self.tab_2 = QtWidgets.QWidget()
self.tab_2.setObjectName("tab_2")
self.tabWidget.addTab(self.tab_2, "")
self.pushButton = QtWidgets.QPushButton(Dialog)
self.pushButton.setGeometry(QtCore.QRect(280, 70, 211, 71))
self.pushButton.setObjectName("pushButton")
self.retranslateUi(Dialog)
QtCore.QMetaObject.connectSlotsByName(Dialog)
self.pushButton.clicked.connect(lambda: EmbTerminal.run_command(EmbTerminal(), "ls"))
def retranslateUi(self, Dialog):
_translate = QtCore.QCoreApplication.translate
Dialog.setWindowTitle(_translate("Dialog", "Dialog"))
self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab), _translate("Dialog", "Tab 1"))
self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_2), _translate("Dialog", "Tab 2"))
self.pushButton.setText(_translate("Dialog", "ls"))
from terminal5 import EmbTerminal
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
Dialog = QtWidgets.QDialog()
ui = Ui_Dialog()
ui.setupUi(Dialog)
Dialog.show()
sys.exit(app.exec_())
You should consider the following:
You should not modify the code generated by Qt Designer (unless you understand its logic)
Do not implement the logic in the class generated by Qt Designer, it is advisable to create a new class that inherits from the appropriate widget and use the other class to fill it.
In your case the problem is that the EmbTerminal() object in lambda: EmbTerminal.run_command(EmbTerminal(), "ls") only exists while the lambda is running, but the lambda runs for a very short time causing the command not to be sent causing the error.
Considering the above, the solution is:
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_Dialog(object):
def setupUi(self, Dialog):
Dialog.setObjectName("Dialog")
Dialog.resize(745, 496)
self.tabWidget = QtWidgets.QTabWidget(Dialog)
self.tabWidget.setGeometry(QtCore.QRect(100, 190, 561, 261))
self.tabWidget.setObjectName("tabWidget")
self.pushButton = QtWidgets.QPushButton(Dialog)
self.pushButton.setGeometry(QtCore.QRect(280, 70, 211, 71))
self.pushButton.setObjectName("pushButton")
self.retranslateUi(Dialog)
QtCore.QMetaObject.connectSlotsByName(Dialog)
def retranslateUi(self, Dialog):
_translate = QtCore.QCoreApplication.translate
Dialog.setWindowTitle(_translate("Dialog", "Dialog"))
self.pushButton.setText(_translate("Dialog", "ls"))
from terminal5 import EmbTerminal
class Dialog(QtWidgets.QDialog, Ui_Dialog):
def __init__(self, parent=None):
super().__init__(parent)
self.setupUi(self)
self.terminal = EmbTerminal()
self.tabWidget.addTab(self.terminal, "Terminal")
self.pushButton.clicked.connect(self.on_clicked)
#QtCore.pyqtSlot()
def on_clicked(self):
self.terminal.run_command("ls")
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
w = Dialog()
w.show()
sys.exit(app.exec_())
On the other hand if you are only going to send commands then it is not necessary to store the QProcess, instead use QProcess: startDetached and make run_command a classmethod:
class EmbTerminal(QtWidgets.QWidget):
# ...
#staticmethod
def run_command(command = "ls" ):
program = "tmux"
options = []
options.extend(["send-keys"])
options.extend([command])
options.extend(["Enter"])
QtCore.QProcess.startDetached(program, options)

PyQt5 keep window on top by clicking button

I am trying to keep window by a Pin button. Here is the code:
import sys
from PyQt5.QtWidgets import QApplication, QWidget, QVBoxLayout, QPushButton, QPushButton
from PyQt5 import QtCore
class App(QWidget):
def __init__(self):
super().__init__()
self.title = 'Keep Going'
self.width = 480
self.height = 360
self.initUI()
def initUI(self):
self.setWindowTitle(self.title)
self.setFixedSize(self.width, self.height)
self.layout = QVBoxLayout()
self.button = QPushButton('PinTop')
self.button.setCheckable(True)
self.button.clicked.connect(self.winPinTop)
self.layout.addWidget(self.button)
# add tabs to widget
self.setLayout(self.layout)
self.show()
def winPinTop(self):
print('Pin')
button = self.sender()
if button.isChecked():
print('on top')
self.setWindowFlags(QtCore.Qt.WindowStaysOnTopHint)
self.show()
else:
print('no top')
self.setWindowFlags(self.windowFlags())
self.show()
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = App()
sys.exit(app.exec_())
The window can not keep on top after clicking the button. I don't know how to fix this.
Infomation may help:
Python 3.6.8
PyQt version: 5.13.0
Ubuntu 19.04
UPDATE
I replace QWidget with QMainWindow class to check this bug.
import sys
from PyQt5.QtWidgets import QMainWindow,QApplication, QWidget, QVBoxLayout, QPushButton, QPushButton
from PyQt5 import QtCore
class App(QMainWindow):
def __init__(self):
super().__init__()
self.title = 'Keep Going'
self.width = 480
self.height = 360
self.initUI()
def initUI(self):
self.setWindowTitle(self.title)
win = QWidget()
win.setFixedSize(self.width, self.height)
layout = QVBoxLayout()
button = QPushButton('PinTop')
button.setCheckable(True)
button.clicked.connect(self.winPinTop)
layout.addWidget(button)
# add tabs to widget
win.setLayout(layout)
self.setCentralWidget(win)
self.show()
def winPinTop(self):
print('Pin')
button = self.sender()
if button.isChecked():
print('on top')
self.setWindowFlags(QtCore.Qt.WindowStaysOnTopHint | QtCore.Qt.Dialog )
print(self.windowFlags())
self.show()
else:
print('no top')
self.setWindowFlags(self.windowFlags() & ~QtCore.Qt.WindowStaysOnTopHint )
print(self.windowFlags())
self.show()
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = App()
sys.exit(app.exec_())
The problem is still here.
UPDATE 2019-9-11
After remove the show function. I can get the window on top.
def winPinTop(self):
print('Pin')
button = self.sender()
if button.isChecked():
print('on top')
self.setWindowFlags(QtCore.Qt.WindowStaysOnTopHint | QtCore.Qt.Dialog )
print(self.windowFlags())
#self.show()
else:
print('no top')
self.setWindowFlags(self.windowFlags() & ~QtCore.Qt.WindowStaysOnTopHint )
print(self.windowFlags())
#self.show()
But the window will close after I click the pin button. When I show this window, it stays on the top.
I don't know why this happened.
Reference: PyQt: Always on top

Set scroll area initially moved

I need to create a big widget inside a scroll area and initially set both sliders in the middle of the bar. The scroll bar does not work, the widgets are not well connected I think.
MRE:
from PyQt5 import QtCore, QtWidgets
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QWidget
import sys
class Diedrico(QWidget):
def __init__(self, parent=None):
super().__init__(parent)
# Draws stuff
class UiVentana(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super(UiVentana, self).__init__(parent)
ventana.resize(1500, 1015)
ventana.setFixedSize(1500, 1015)
self.widget_central = QtWidgets.QWidget(ventana)
scrol = QtWidgets.QScrollArea(self.widget_central)
scrol.setWidgetResizable(True)
scrol.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn)
scrol.setGeometry(QtCore.QRect(1010, 510, 470, 460))
self.Diedrico = Diedrico(scrol)
self.Diedrico.setGeometry(QtCore.QRect(0, 0, 1000, 1000))
# This widget should be big enough to use the scroll bar, but it does not work
ventana.setCentralWidget(self.widget_central)
ventana.show()
if __name__ == "__main__":
app = QtWidgets.QApplication([])
ventana = QtWidgets.QMainWindow()
ui = UiVentana()
sys.exit(app.exec_())
It seems that the problem comes from scrol.setWidgetResizable(True), which seems to resize the content... setting this to False worked for me.
Also, to center the scrollbar, there are a few options, like setting the value of the verticalScrollBar or using ensureVisible(x, y).
A working solution:
from PyQt5 import QtCore, QtWidgets
import sys
class UiVentana(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super(UiVentana, self).__init__(parent)
self.setupUi()
self.label.setGeometry(QtCore.QRect(10, 0, 282, 331))
self.label.setText("this is a long text\n" * 100)
self.scrollArea.verticalScrollBar().setValue(300)
def setupUi(self):
self.resize(800, 600)
self.centralwidget = QtWidgets.QWidget(self)
self.scrollArea = QtWidgets.QScrollArea(self.centralwidget)
self.scrollArea.setGeometry(QtCore.QRect(470, 330, 301, 211))
self.scrollArea.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn)
self.scrollArea.setWidgetResizable(False)
self.scrollAreaWidgetContents = QtWidgets.QWidget()
self.scrollAreaWidgetContents.setGeometry(QtCore.QRect(0, 0, 282, 10000))
self.label = QtWidgets.QLabel(self.scrollAreaWidgetContents)
self.scrollArea.setWidget(self.scrollAreaWidgetContents)
self.setCentralWidget(self.centralwidget)
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
ui = UiVentana()
ui.show()
sys.exit(app.exec_())

PyQt change picture with keyboard button

this is my first post here and I haven't seen it anywhere so hopefully it is ok. I am trying to change the displayed image with a keyboard click (think slideshow). This is my code so far:
import sys
from PyQt5.QtWidgets import QApplication, QWidget, QLabel
from PyQt5.QtGui import QPixmap
from PyQt5.QtCore import Qt
import os
class App(QWidget):
def __init__(self):
super().__init__()
self.title = 'Document Analysis'
self.left = 30
self.top = 30
self.width = 640
self.height = 480
self.imagenumber=0
self.initUI()
def keyPressEvent(self, event):
key=event.key()
if key==Qt.Key_Right:
self.imagenumber=self.imagenumber+1
self.showimage(self.imagenumber)
self.show()
else:
super(self).keyPressEvent(event)
def initUI(self):
self.setWindowTitle(self.title)
self.setGeometry(self.left, self.top, self.width, self.height)
self.showimage(0)
self.show()
def showimage(self,imagenumber):
label = QLabel(self)
directory = "C:\\Desktop\\Pictures"
imagelist = os.listdir(directory)
pixmap = QPixmap(directory + '\\' + imagelist[imagenumber])
label.setPixmap(pixmap)
self.resize(pixmap.width() + 500, pixmap.height())
self.show()
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = App()
sys.exit(app.exec_())
It seems to be sort of getting somewhere, the first image displays just fine, and I know imagenumber does change, and when I stopped it from showing at first it resized the window but still didn't show the image. Any suggestions on what I am doing wrong?
This is part of a larger project which is the reason for the extra space on the side of the picture, but help would be appreciated.
You're close. Try the following...
import sys
from PyQt5.QtWidgets import QApplication, QWidget, QLabel, QVBoxLayout
from PyQt5.QtGui import QPixmap
from PyQt5.QtCore import Qt
import os
class App(QWidget):
def __init__(self):
super().__init__()
self.title = 'Document Analysis'
self.left = 30
self.top = 30
self.width = 640
self.height = 480
self.imagenumber=0
self.initUI()
def keyPressEvent(self, event):
key=event.key()
if key==Qt.Key_Right:
self.imagenumber=self.imagenumber+1
self.showimage(self.imagenumber)
# self.show()
else:
super(self).keyPressEvent(event)
def initUI(self):
layout = QVBoxLayout()
self.setLayout(layout)
self.label = QLabel(self)
layout.addWidget(self.label)
self.setWindowTitle(self.title)
self.setGeometry(self.left, self.top, self.width, self.height)
self.showimage(0)
self.show()
def showimage(self,imagenumber):
# label = QLabel(self)
directory = "C:\\Desktop\\Pictures"
imagelist = os.listdir(directory)
pixmap = QPixmap(directory + '\\' + imagelist[imagenumber])
# label.setPixmap(pixmap)
self.label.setPixmap(pixmap)
self.resize(pixmap.width() + 500, pixmap.height())
# self.show()
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = App()
sys.exit(app.exec_())
Mainly, you need a persistent label. You also only need to call show() once.

Resources