PyQt5 GUI scaling issue and pointer misaligned when adding QWebEngineView - python

I'm developing a GUI that embeds a web browser using QtWebEngineView. Whenever I add it, a scaling issue comes up. The pointer is not aligned correctly, and everything becomes fuzzy.
I have already looked at the problems referenced here, however I am still looking for a different solution:
PyQt5 QWebEngineView causes blurry/fuzzy scaling issue
PyQt WebEngineView interferes with MainMenu
The scaling issue does get fixed when I use main.showFullScreen() (but then my combobox doesn't show any options, however you can still chose them, though this isn't the immediate issue.) The other solution was to rollback the graphics driver but I didn't find it practical since I'm trying to distribute this application company wide.
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWebEngineWidgets import QWebEngineView
import sys
import pandas as pd
districtDF = pd.read_csv('districts.csv')
distlist = []
class Web(QWebEngineView):
def load(self, url):
self.setUrl(QUrl(url))
class main_window(QMainWindow):
def __init__(self, *args, **kwargs):
super(main_window, self).__init__(*args, **kwargs)
self.setWindowTitle('Test')
self.setGeometry(50, 50, 600, 700)
layout = QVBoxLayout()
combo = QComboBox(self)
for x in districtDF['dist']:
combo.addItem(x)
combo.move(50,50)
combo.setGeometry(225, 50, 150, 30)
web = Web()
web.load("https://www.google.com/")
layout.addWidget(combo)
layout.addWidget(web)
widget = QWidget()
widget.setLayout(layout)
self.setCentralWidget(widget)
self.show()
app = QApplication(sys.argv)
main = main_window()
main.showFullScreen()
app.exec_()
Is there any way to fix this and be able to keep a windowed view?

Related

Pushing QWidget Window to topmost in Python

I'm new to Python and have mostly learnt C# in the past. I am creating a QWidget class:
class Window(QWidget):
def __init__(self, gif, width, height):
super().__init__()
self.setGeometry(400, 200, width, height)
self.setWindowTitle("Python Run GIF Images")
self.setWindowIcon(QIcon('icons/qt.png'))
label = QLabel(self)
movie = QMovie(gif)
label.setMovie(movie)
movie.start()
And then define a function that creates a QApplication and then the Window:
def run_gif(gif, width, height):
app = QApplication([])
window = Window(gif, width, height)
window.show()
app.exec()
app.shutdown()
My issue is getting the gif to show topmost when it is launched. There is a Topmost property you can set on a Winform in C# which means no other window or other app you click on will cover the Window. This isn't essential but I want it to at least be shown above the code editor it is launched from so that the user doesn't have to select the Window to see the gif contained in the Window. I've spent hours looking at properties I can set either in the class or the method and not getting the result I need.
However, when I call the run_gif method for the second time, it does show it topmost, but along with the below exception (at least I think it's an exception from what I'm reading, it doesn't affect the running of the program other than printing to the console).
QApplication::regClass: Registering window class 'Qt640ScreenChangeObserverWindow' failed. (Class already exists.)
The only advice I can find on this error is not Python-specific and I don't really understand it. Maybe I'm being a bit ambitious for my early stage learning Python but not really seeing anything much on this error.
This is using PySide6.
Using setWindowFlag(Qt.WindowType.WindowStaysOnTopHint, True) seems to be working for me so far.
Example:
from PySide6.QtWidgets import *
from PySide6.QtCore import *
from PySide6.QtGui import *
class Window(QWidget):
def __init__(self, parent=None):
super().__init__(parent=parent)
self.layout = QVBoxLayout(self)
self.resize(200,100)
self.label = QLabel("Always on top...")
self.layout.addWidget(self.label)
self.setWindowFlag(Qt.WindowType.WindowStaysOnTopHint, True) # <--
if __name__ == '__main__':
app = QApplication([])
window = Window()
window.show()
app.exec()

Unable to add a QTextEdit inside QTreeWidget

I'm trying to add an option for a QTreeWidget to have multi line editing, which I would assume will require a QTextEdit. The problem is that the examples I've found online just do not work.
The answers I've found have all pointed to using tree.setItemWidget(item, column, widget), but If I add that line, the window just doesn't appear at all. What am I doing wrong in this case?
Here is my example code that has the issue:
import sys
from Qt import QtWidgets, QtCore
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, parent=None, **kwargs):
super(MainWindow, self).__init__(parent, **kwargs)
#Add tree widget to window
tree = QtWidgets.QTreeWidget()
tree.setHeaderItem(QtWidgets.QTreeWidgetItem(['col1', 'col2']))
self.setCentralWidget(tree)
#Create items
topLevelButton = QtWidgets.QPushButton('button')
topLevelItem = QtWidgets.QTreeWidgetItem(['test button', 'line edit'])
topLevelItem.setFlags(topLevelItem.flags() | QtCore.Qt.ItemIsEditable)
#Add items to tree widget
tree.addTopLevelItem(topLevelItem)
tree.setItemWidget(topLevelItem, 0, topLevelButton) #the window will not load if this line is not commented out
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
window = MainWindow()
app.setActiveWindow(window)
window.show()
sys.exit(app.exec_())
I've tried it in PySide (2.7) and PySide2 (3.7).
Edit: For Python 3 at least, it seemed to be an issue with PySide2, where forcing PyQt5 somehow fixed whatever it was. I'm still unable to launch with Python 2 as I can't really install PyQt4.
Edit 2: It actually causes a crash if you use it in a program such as Nuke that uses PySide, I may need to ask a more specific question if I can't figure it out from this one.
Sorry, PyQt5 is working.
import sys
#from Qt import QtWidgets, QtCore
from PyQt5 import QtWidgets, QtCore # <---
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, parent=None, **kwargs):
super(MainWindow, self).__init__(parent, **kwargs)
# Add tree widget to window
tree = QtWidgets.QTreeWidget()
tree.setHeaderItem(QtWidgets.QTreeWidgetItem(['col1', 'col2']))
self.setCentralWidget(tree)
# Create items
topLevelButton = QtWidgets.QPushButton('button')
topLevelItem = QtWidgets.QTreeWidgetItem(['test button', 'line edit'])
topLevelItem.setFlags(topLevelItem.flags() | QtCore.Qt.ItemIsEditable)
# Add items to tree widget
tree.addTopLevelItem(topLevelItem)
tree.setItemWidget(topLevelItem, 0, topLevelButton) # ??? the window will not load if this line is not commented out
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
window = MainWindow()
app.setActiveWindow(window) # ???
window.show()
sys.exit(app.exec_())

PyQt WebEngineView interferes with MainMenu

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.

Access QT Designer Objects Programmatically

Disclaimer: New to both python and qt designer
QT Designer 4.8.7
Python 3.4
PyCharm 5.0.3
Question - How do I add controls to the main form or a scroll area widget on the main form (created in QT Designer) programmatically?
I have created a MainWindow in qt designer and added my widgets. The following is the entire test program in PyCharm:
import sys
from PyQt4 import QtGui, QtCore, uic
from PyQt4.QtGui import *
from PyQt4.QtCore import *
qtCreatorFile = "programLauncher.ui"
Ui_MainWindow, QtBaseClass = uic.loadUiType(qtCreatorFile)
class MyApp(QtGui.QMainWindow, Ui_MainWindow):
def __init__(self):
QtGui.QMainWindow.__init__(self)
Ui_MainWindow.__init__(self)
self.setupUi(self)
# Cannot resize or maximize
self.setFixedSize(1045, 770)
# Add button test
self.dateLabel = QtGui.QLabel("Test")
self.pushButton = QtGui.QPushButton('Test button')
# self.scrollArea_programs.addWidget()
grid = QtGui.QGridLayout()
# self.scrollArea_programs.addWidget(self.pushButton)
grid.addWidget(self.dateLabel,0,0)
grid.addWidget(self.pushButton,0,1)
self.setLayout(grid)
self.pushButton_exit.clicked.connect(self.closeEvent)
def closeEvent(self):
QtGui.QApplication.quit()
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
window = MyApp()
window.show()
sys.exit(app.exec_())
As you can see I tried to add controls to a grid but nothing shows up when the program runs - I have also tried to add a control to the scroll area. Can someone help me to just add 1 control to the scroll area at run time - so then I can know the proper way to do it or "a" proper way to do this.
Thanks in advance
Without having access to your programLauncher.ui and making minimal changes to your posted code, you can add your UI elements to the window like so:
from PyQt4 import QtGui
import sys
class MyApp(QtGui.QMainWindow):
def __init__(self):
QtGui.QMainWindow.__init__(self)
# Cannot resize or maximize
self.setFixedSize(1045, 770)
widget = QtGui.QWidget(self)
self.setCentralWidget(widget)
# Add button test
self.dateLabel = QtGui.QLabel("Test")
self.pushButton = QtGui.QPushButton('Test button')
grid = QtGui.QGridLayout()
grid.addWidget(self.dateLabel, 0, 0)
grid.addWidget(self.pushButton, 0, 1)
widget.setLayout(grid)
self.pushButton.clicked.connect(self.closeEvent)
def closeEvent(self, event):
QtGui.QApplication.quit()
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
window = MyApp()
window.show()
sys.exit(app.exec_())
This will get the controls on the screen, although the layout leaves a lot to be desired. You may have to make modifications to this based on what's in your .ui file. One thing that you'll want to note in this example is that the QMainWindow needs a central widget (widget in the example above). You then set the layout on that widget.
You can use the designer to create your .ui file
The you can load it in your .py using something like:
from PyQt4 import QtCore, QtGui, uic
class my_win(QtGui.QMainWindow):
def __init__(self):
self.ui = uic.loadUi('my_ui.ui',self)
then you can access all your widgets with something like
self.ui.actionQuit.triggered.connect(QtGui.qApp.quit)
or
self.ui.my_button.triggered.connect(self.do_someting)
Thanks to JCVanHamme (the programLauncher.ui hint) and also outside help I now learned most of what I need to know to access MainWindow at run time. So for anyone interested in this beginner tip:
Take a blank form in QT Designer
Add a control
Run pyuic4 batch file
Take a look at the generated .py file to learn EVERYTHING about how to add controls.
Don't let the power go to your head - cheers

How can I make link on web page in window using pyqt4?

I have a problem.
Can I make a link on the web page in the window and when the user clicks on it, the web page will be open in the browser.
For example:
import sys
from PyQt4 import QtGui, QtCore
app = QtGui.QApplication(sys.argv)
main = QtGui.QWidget()
main.setGeometry(200, 200, 200, 100)
label = QtGui.QLabel('Stackoverflow/')
box = QtGui.QVBoxLayout()
box.addWidget(label)
main.setLayout(box)
main.show()
sys.exit(app.exec_())
Is it really?
It is of course good that you found answer, but there is special class, which allows you to open URL in default browser or files in default editors/players etc. It is QDesktopServices. For example:
from PyQt5.QtGui import QDesktopServices
from PyQt5.QtCore import QUrl
class MainWindow(QMainWindow, Ui_MainWindow):
def link(self, linkStr):
QDesktopServices.openUrl(QUrl(linkStr))
def __init__(self):
super(MainWindow, self).__init__()
# Set up the user interface from Designer.
self.setupUi(self)
self.label.linkActivated.connect(self.link)
self.label.setText('Stackoverflow/')
This example is definitely larger, but you should know about QDesktopServices, because it is very useful class.
Sorry. I have already searched the answer.
label.setText('Link')
label.setOpenExternalLinks(True)

Categories

Resources