I'm building a GUI with PyQt, and I'd like to make it possible to stop all the buttons doing anything while code is running. Lets say the user is copying a lot of data from a table - it would be easy for them to click another button while it is happening even if the cursor has changed to the egg timer. Any ideas or workarounds for this without going through all buttons and greying them out one by one? I'd be happy with a workaround too!
Thanks for any ideas,
Pete
You could use a modal QDialog. From the QDialog pyqt documentation:
A modal dialog is a dialog that blocks input
to other visible windows in the same application.
Also, QProgressDialog is a very convenient tool to handle blocking action in a very simple way. Here is an example :
from PyQt4 import QtGui, QtCore
from time import sleep
class Test(QtGui.QDialog):
def __init__(self, parent=None):
super(Test, self).__init__(parent)
button = QtGui.QPushButton("Button")
hbox = QtGui.QHBoxLayout()
hbox.addWidget(button)
self.setLayout(hbox)
button.clicked.connect(self.slot)
def slot(self):
progress = QtGui.QProgressDialog(self)
progress.setWindowModality(QtCore.Qt.WindowModal)
progress.setLabel(QtGui.QLabel("Doing things..."))
progress.setAutoClose(True)
for i in range(101):
progress.setValue(i);
sleep(0.05)
if progress.wasCanceled():
break
if __name__=="__main__":
import sys
app = QtGui.QApplication(sys.argv)
myapp = Test()
myapp.show()
sys.exit(app.exec_())
Related
I'm trying to create an application that contains a web browser within it, but when I add the web browser my menu bar visually disappears but functionally remains in place. The following are two images, one showing the "self.centralWidget(self.web_widget)" commented out, and the other allows that line to run. If you run the example code, you will also see that while visually the entire web page appears as if the menu bar wasn't present, you have to click slightly below each entry field and button in order to activate it, behaving as if the menu bar was in fact present.
Web Widget Commented Out
Web Widget Active
Example Code
import os
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtWebEngineWidgets import *
class WebPage(QWebEngineView):
def __init__(self, parent=None):
QWebEngineView.__init__(self)
self.current_url = ''
self.load(QUrl("https://facebook.com"))
self.loadFinished.connect(self._on_load_finished)
def _on_load_finished(self):
print("Url Loaded")
class MainWindow(QMainWindow):
def __init__(self, parent=None):
# Initialize the Main Window
super(MainWindow, self).__init__(parent)
self.create_menu()
self.add_web_widet()
self.show()
def create_menu(self):
''' Creates the Main Menu '''
self.main_menu = self.menuBar()
self.main_menu_actions = {}
self.file_menu = self.main_menu.addMenu("Example File Menu")
self.file_menu.addAction(QAction("Testing Testing", self))
def add_web_widet(self):
self.web_widget = WebPage(self)
self.setCentralWidget(self.web_widget)
if __name__ == "__main__":
app = QApplication(sys.argv)
main_window = MainWindow()
main_window.showMaximized()
sys.exit(app.exec_()) # only need one app, one running event loop
Development Environment
Windows 10, PyQt5, pyqt5-5.9
EDIT
The problem doesn't seem to be directly related to the menu bar. Even removing the menu bar the issue still occurs. That said, changing from showMaximized() to showFullScreen() does seem to solve the problem.
I no longer believe this is an issue with PyQt5 specifically but rather a problem with the graphics driver. Specifically, if you look at Atlassian's HipChat application it has a similar problem which is documented here:
https://jira.atlassian.com/browse/HCPUB-3177
Some individuals were able to solve the problem by running the application from the command prompt with the addendum "--disable-gpu" but that didn't work for my python application. On the other hand, rolling back the Intel(R) HD Graphics Driver did solve my problem. Version 21.20.16.4627 is the one that seems to be causing problems.
I'm working on a small application for work w/ python and PyQt4 for the GUI. What I'm trying to accomplish is having a tabbed GUI where when a user clicks on a menu item, the action taken adds a tab to the QTabWidget. I'm currently having trouble getting an action to do such a thing. I've tried creating the GUI by hand and with QT designer, but I cant figure out how, if at all possible, to get an action to add a tab to the QTabWidget. This is my python code:
import sys
from PyQt4 import QtGui, uic
class TestGUI(QtGui.QMainWindow):
def __init__(self):
super(TestGUI, self).__init__()
uic.loadUi('TEST.ui', self)
self.show()
self.actionAdd_Tab.triggered.connect(addTab)
def addTab():
print 'This works'
#Add new tab to GUI
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
window = TestGUI()
sys.exit(app.exec_())
Pressing the menu item prints 'This works' to the console, so I know that its calling the addTab() function, but how do I get it to add a Tab?
Let me know if you would like to see the .ui file if it will help
The handler for your action needs to create a tab label, and also a widget for the contents of the tab, so that they can be added to the tabwidget.
As a start, try something like this:
import sys
from PyQt4 import QtGui, uic
class TestGUI(QtGui.QMainWindow):
def __init__(self):
super(TestGUI, self).__init__()
uic.loadUi('TEST.ui', self)
self.actionAdd_Tab.triggered.connect(self.handleAddTab)
def handleAddTab(self):
contents = QtGui.QWidget(self.tabWidget)
layout = QtGui.QVBoxLayout(contents)
# add other widgets to the contents layout here
# i.e. layout.addWidget(widget), etc
self.tabWidget.addTab(contents, 'Tab One')
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
window = TestGUI()
window.show()
sys.exit(app.exec_())
QTabWidget's addTab() method, coincidentally named the same, adds a tab.
I'm trying to set up an app in Linux using PyQt4 designer and I'm struggling to connect signals and slots to it. Right now all I want it to do is connect a button clicked signal to a custom slot, saveEnergyScheme which simply prints 'energy list' to the terminal.
I've translated the .ui code for my app to a python class with pyuic4 -w sumcorr.ui > sumcorr_ui.py. This created a class in the sumcorr_ui.py module called SumCorr_ui:
class SumCorr_ui(QtGui.QMainWindow, Ui_SumCorr_ui):
def __init__(self, parent=None, f=QtCore.Qt.WindowFlags()):
QtGui.QMainWindow.__init__(self, parent, f)
self.setupUi(self)
I then made my app as a custom widget and tried to add a simple signal-slot connection to a button to show it works:
from PyQt4 import QtGui, QtCore
from sumcorr_ui import SumCorr_ui
class SumCorr(SumCorr_ui):
def __init__(self):
SumCorr_ui.__init__(self)
self.save_energies_button.clicked.connect(self.saveEnergyScheme)
def saveEnergyScheme(self):
print 'energyList'
if __name__ == '__main__':
import sys
app = QtGui.QApplication(sys.argv)
mySumCorr = QtGui.QMainWindow()
ui = SumCorr()
ui.setupUi(mySumCorr)
mySumCorr.show()
sys.exit(app.exec_())
I expect to get the line 'energy list' when I click the button named save_energies_button, but nothing happens. Could this be because I haven't built the UI as a widget, but as a main window? Why doesn't it print out??
Try to add ui.show() and you'll see that your code is creating two different windows, one should have the signal connected and one doesn't. That's because you are showing only the mySumCorr window, but you call only setupUi on it, which does not connect the signal.
When you create the SumCorr instance, you are creating a window and setting it up, then, by no reason, you do ui.setupUi(mySumCorr), which setups the mySumCorr instance without connecting the signal, and you show this last window.
I believe your code should be like this:
class SumCorr(QtGui.QMainWindow, Ui_SumCorr_ui):
def __init__(self):
SumCorr_ui.__init__(self)
self.setupUi(self)
self.save_energies_button.clicked.connect(self.saveEnergyScheme)
def saveEnergyScheme(self):
print 'energyList'
if __name__ == '__main__':
import sys
app = QtGui.QApplication(sys.argv)
mySumCorr = SumCorr()
mySumCorr.show()
sys.exit(app.exec_())
Note that it doesn't make any sense to have a SumCorr_ui class, that's because Qt is a UI library so you are just introducing a worthless level of abstraction. The designer file already gives you an abstraction over the ui layout.
I just started dwelling into the realm of Qt (coming from PyGTK) and I'm using PySide. So I found this great example on another answer here on stack exchange.
import sys
from PySide.QtCore import *
from PySide.QtGui import *
from PySide.QtWebKit import *
app = QApplication(sys.argv)
web = QWebView()
web.settings().setAttribute(
QWebSettings.WebAttribute.DeveloperExtrasEnabled, True)
# or globally:
# QWebSettings.globalSettings().setAttribute(
# QWebSettings.WebAttribute.DeveloperExtrasEnabled, True)
web.load(QUrl("http://www.google.com"))
web.show()
inspect = QWebInspector()
inspect.setPage(web.page())
inspect.show()
sys.exit(app.exec_())
My question is as follows, how do I make the inspector show up in the same window instead of a new one? I understand I need to add the QWebInspector to another widget inside the main window (a vbox for example), what I want to know is how to connect that event to the signal the context menu "Inspect" triggers. In PyGTK I would need to use .connect() but I can't find the right SIGNAL for this specific action.
Thanks for your time guys/gals
It shouldn't be necessary to do anything special for the context menu to work. Just add an inspector widget to your layout, and hide() it to start with. The default context menu action can then show() the inspector as needed.
A slightly trickier issue is how to hide the inspector again once it's shown, as there doesn't seem to be a corresponding context menu item for that.
The demo script below simply creates a keyboard shortcut to hide/show the inspector:
from PySide import QtGui, QtCore, QtWebKit
class Window(QtGui.QWidget):
def __init__(self):
QtGui.QWidget.__init__(self)
self.view = QtWebKit.QWebView(self)
self.view.settings().setAttribute(
QtWebKit.QWebSettings.WebAttribute.DeveloperExtrasEnabled, True)
self.inspector = QtWebKit.QWebInspector(self)
self.inspector.setPage(self.view.page())
self.inspector.hide()
self.splitter = QtGui.QSplitter(self)
self.splitter.addWidget(self.view)
self.splitter.addWidget(self.inspector)
layout = QtGui.QVBoxLayout(self)
layout.addWidget(self.splitter)
QtGui.QShortcut(QtGui.QKeySequence('F7'), self,
self.handleShowInspector)
def handleShowInspector(self):
self.inspector.setShown(self.inspector.isHidden())
if __name__ == '__main__':
import sys
app = QtGui.QApplication(sys.argv)
window = Window()
window.view.load(QtCore.QUrl('http://www.google.com'))
window.show()
sys.exit(app.exec_())
I want to do hover. I saw an example and then write a script which will be use as I made program. I am facing one problem that hover only occur if you put mouse on the left corner of button. I want that it will happen for all the button that if i move cursor on button then it should change.
Here is my code:
from PyQt4 import QtGui, QtCore
from PyQt4.QtCore import pyqtSignal
import os,sys
class HoverButton(QtGui.QToolButton):
def enterEvent(self,event):
print("Enter")
button.setStyleSheet("background-color:#45b545;")
def leaveEvent(self,event):
button.setStyleSheet("background-color:yellow;")
print("Leave")
app = QtGui.QApplication(sys.argv)
widget = QtGui.QWidget()
button = QtGui.QToolButton(widget)
button.setMouseTracking(True)
buttonss = HoverButton(button)
button.setIconSize(QtCore.QSize(200,200))
widget.show()
sys.exit(app.exec_())
Is this what you're looking for
from PyQt4 import QtGui, QtCore
from PyQt4.QtCore import pyqtSignal
import os,sys
class Main(QtGui.QWidget):
def __init__(self, parent=None):
super(Main, self).__init__(parent)
layout = QtGui.QVBoxLayout(self) # layout of main widget
button = HoverButton(self)
button.setIconSize(QtCore.QSize(200,200))
layout.addWidget(button) # set your button to the widgets layout
# this will size the button nicely
class HoverButton(QtGui.QToolButton):
def __init__(self, parent=None):
super(HoverButton, self).__init__(parent)
self.setMouseTracking(True)
def enterEvent(self,event):
print("Enter")
self.setStyleSheet("background-color:#45b545;")
def leaveEvent(self,event):
self.setStyleSheet("background-color:yellow;")
print("Leave")
app = QtGui.QApplication(sys.argv)
main = Main()
main.show()
sys.exit(app.exec_())
In your code you had a button in a button and the nested button wasn't assigned to a QLayout widget. Although, I'm not sure why you're adding a button inside of a button. One thing that I've learned from working with GUI's is that it's so much easier if you modularize your code. Now you can take this custom button and apply it somewhere else.
You should use the stylesheet as
QToolButton:hover
{
background-color: rgb(175,175,175);
}
You probably want focus and blur, rather than enter and leave will only fire when the mouse actually enters or leaves the boundary of the button and will probably just be short duration impulses rather than toggles. focus and blur will toggle with the hover.