QAxWidget glitches when resizing GUI window - python

I am currently exploring the possibilities of displaying and working with PowerPoint presentations in a GUI using PyQt5/PyQt6 and Python. For that I found the most promising solution to be using a QAxWidget. Loading and displaying the pptx-file works fine, but unfortunately I noticed glitches when resizing the window of the GUI.
As a minimal example I used the following tutorial from the official Qt docs:
https://doc.qt.io/qtforpython/examples/example_axcontainer__axviewer.html?highlight=qaxwidget
After the QAxWidget()-initialization i just added the following line:
self.axWidget.setControl(r"C:\path\to\file\presentation.pptx")
Full code (taken from: https://doc.qt.io/qtforpython/examples/example_axcontainer__axviewer.html?highlight=qaxwidget):
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
"""PySide6 Active Qt Viewer example"""
import sys
from PyQt5.QtWidgets import qApp
from PySide6.QtAxContainer import QAxSelect, QAxWidget
from PySide6.QtGui import QAction
from PySide6.QtWidgets import (QApplication, QDialog,
QMainWindow, QMessageBox, QToolBar)
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
toolBar = QToolBar()
self.addToolBar(toolBar)
fileMenu = self.menuBar().addMenu("&File")
loadAction = QAction("Load...", self, shortcut="Ctrl+L", triggered=self.load)
fileMenu.addAction(loadAction)
toolBar.addAction(loadAction)
exitAction = QAction("E&xit", self, shortcut="Ctrl+Q", triggered=self.close)
fileMenu.addAction(exitAction)
aboutMenu = self.menuBar().addMenu("&About")
aboutQtAct = QAction("About &Qt", self, triggered=qApp.aboutQt)
aboutMenu.addAction(aboutQtAct)
self.axWidget = QAxWidget()
self.axWidget.setControl(r"C:\path\to\file\presentation.pptx")
self.setCentralWidget(self.axWidget)
def load(self):
axSelect = QAxSelect(self)
if axSelect.exec() == QDialog.Accepted:
clsid = axSelect.clsid()
if not self.axWidget.setControl(clsid):
QMessageBox.warning(self, "AxViewer", f"Unable to load {clsid}.")
if __name__ == '__main__':
app = QApplication(sys.argv)
mainWin = MainWindow()
availableGeometry = mainWin.screen().availableGeometry()
mainWin.resize(availableGeometry.width() / 3, availableGeometry.height() / 2)
mainWin.show()
sys.exit(app.exec())
When resizing the window of the GUI, there appear some glitches underneath:
An animation that shows the result while resizing:
Unfortunately I haven't found many resources I could use where a QAxWidget is used in combination with Python to figure this out myself. That's why I'm here to ask if anyone out there might have a solution for getting rid of those glitches.

I got rid of the glitches by installing an event filter to the QAxWidget using self.axWidget.installEventFilter(self).
This will call the eventFilter()-method of the QMainWindow which I set up like this: (ReportDefinitionTool is the subclass of QMainWindow here.)
def eventFilter(self, widget: QWidget, event: QEvent):
if event.type() == QEvent.Resize and widget is self.pptx_axwidget:
self.pptx_axwidget.setFixedHeight(int(self.pptx_axwidget.width() / 16 * 9))
return super(ReportDefinitionTool, self).eventFilter(widget, event)
Since the PowerPoint-presentation is displayed in a 16:9 format, this will make sure the QAxWidget does only occupy this space. The glitchy space from the initial question came from the unused space of the QAxWidget.

Related

Widgets are not displayed

I'm currently doing a tutorial on how to create GUI apps from a book called "Modern PyQt" by Joshua Willman and I'm stuck right out of the gate:
I've copy pasted a basic code snippet from the book and tried to tweak it bit by bit instead of reading a bunch of text without any practical trial and error. I can display a window and adjust it's size and properties, but when I try to attach other widgets to the main window, they just don't show up.
Here's what I've got so far:
# First practical example from the book: Pomodoro time manager
import sys
from PyQt5.QtWidgets import QApplication, QWidget, QPushButton
from PyQt5.QtGui import QIcon
class Pomodoro(QWidget):
def __init__(self): # Create default constructor
super().__init__()
self.initializeUI()
def initializeUI(self):
"""Initialize the window and display its contents to the screen."""
self.setGeometry(int((SCREEN_WIDTH-WINDOW_WIDTH)/2),int((SCREEN_HEIGHT-WINDOW_HEIGHT)/2),WINDOW_WIDTH,WINDOW_HEIGHT) # x,y,w,h
self.setWindowTitle('Bortism')
# self.setWindowIcon(QIcon("Borticon.png"))
self.button1 = QPushButton()
self.button1.setText('Button')
self.show()
if __name__ == '__main__':
app = QApplication(sys.argv)
WINDOW_WIDTH, WINDOW_HEIGHT = 1000,600
SCREEN_X, SCREEN_Y, SCREEN_WIDTH, SCREEN_HEIGHT = app.desktop().screenGeometry().getRect()
window = Pomodoro()
sys.exit(app.exec_())
For a widget to be shown as part of another then the requirement is that the first is the child of the second. This can be done by passing the parent or by using a layout (which is also passed to it by the parent). So in your case you must change to:
self.button1 = QPushButton(self)

pyqt5 / qtdesigner textbox default label

I am trying to create a GUI for my python program. One of the tools that I need is a text input box.
Now, I want a text label for this box saying "Please insert texts." Is there a function to add a label that shows inside the input textbox as default and disappear when user click the box to type?
I don't mind to use qt designer or pyqt5 coding.
Thank you guys.
placeholderText : QString
This property holds the line edit's placeholder text
import sys
from PyQt5.QtWidgets import QLineEdit, QVBoxLayout, QApplication, QWidget
class Test(QWidget):
def __init__(self):
super().__init__()
self.lineEdit = QLineEdit(placeholderText="Please insert texts.") # <---
vbox = QVBoxLayout(self)
vbox.addWidget(self.lineEdit)
if __name__ == '__main__':
app = QApplication(sys.argv)
w = Test()
w.show()
sys.exit(app.exec_())
I am begginer like you and my English is not so good. But I recommend you use Qt Designer. It's easier, fastter for you draw your app. I am using pyside2 project and recommend you read docummentatio each widgets you wanna use in PySide2 project and Qt Project. Try code below
enter image description here
import sys
from PySide2.QtWidgets import QApplication
from PySide2.QtWidgets import QDialog
from PySide2.QtWidgets import QTextEdit
from PySide2.QtWidgets import QVBoxLayout
from PySide2.QtCore import Qt
class MainDialog(QDialog):
def __init__(self, parent=None):
super(MainDialog, self).__init__(parent)
# Create Widget TextEdit
self.text = QTextEdit()
# I think that you wanna this function in your program
# https://doc.qt.io/qtforpython/PySide2/QtWidgets/QLineEdit.html?highlight=qlineedit#PySide2.QtWidgets.PySide2.QtWidgets.QLineEdit.setPlaceholderText
# http://doc.qt.io/qt-5/qlineedit.html#placeholderText-prop
self.text.setPlaceholderText('''Yes! this is exactly what I want!
Thank you, what if you have a big text box (more than 10 lines) and
you want to scale up the place holder and align it in center?? ''')
# https://doc.qt.io/qtforpython/PySide2/QtWidgets/QLineEdit.html?highlight=qlineedit#PySide2.QtWidgets.PySide2.QtWidgets.QLineEdit.setAlignment
# http://doc.qt.io/qt-5/qlineedit.html#alignment-prop
self.text.setAlignment(Qt.AlignCenter)
# Layout
layout = QVBoxLayout()
layout.addWidget(self.text)
self.setLayout(layout)
def main():
app = QApplication()
mainDialog = MainDialog()
mainDialog.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()

How to resize a QColorDialog

Is it possible to resize a QColorDialog? I have been unable to get the window to resize appropriately. After the dialog is shown, it reverts to the default size.
An example:
import sys
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
class Window(QWidget):
def __init__(self):
super().__init__()
layout = QVBoxLayout()
push_Button = QPushButton()
layout.addWidget(push_Button)
push_Button.clicked.connect(self.button)
self.setLayout(layout)
def button(self):
color = QColorDialog(self)
color.resize(100,100)
print(color.size()) #Prints 100, 100
color.show()
print(color.size()) #Prints 551, 431
if __name__ == '__main__':
app = QApplication(sys.argv)
window = Window()
window.show()
sys.exit(app.exec_())
The QColorDialog has a fixed size, because it contains several custom widgets which aren't designed to be resizable. It is possble to override these constraints and allow for manual resizing like this:
color = QColorDialog(self)
color.setSizeGripEnabled(True)
color.layout().setSizeConstraint(QLayout.SetNoConstraint)
color.show()
However, as you will see, the layout quickly becomes messed up with even a little bit of resizing. I also found that beyond a certain point, the dialog will actually crash due to floating point exceptions. So I think you will either have to accept it as it is, or perhaps write your own color dialog.

Move QtWidgets.QtWidget using mouse

I want to move a QtWidgets.QtWidget using the mouse (not a QPushButton, QLabel etc.). I've searched everywhere on the web, but couldn't find an answer for this. mousePressEvent seemed to be the way, but it doesn't work.
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_hGUI(QtWidgets.QWidget):
def __init__(self):
QtWidgets.QWidget.__init__(self)
def setupUi(self, hGUI):
hGUI.setObjectName("hGUI")
hGUI.resize(161, 172)
hGUI.setMinimumSize(QtCore.QSize(200, 200))
hGUI.setMaximumSize(QtCore.QSize(200, 200))
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
hGUI = QtWidgets.QWidget()
ui = Ui_hGUI()
ui.setupUi(hGUI)
hGUI.show()
sys.exit(app.exec_())
I'm using Python 3.5, I'm creating the GUI using Qt Designer, then translate it to python code.
Edit: I'm trying to move a borderless windows by click on it.
That's a really simple question sir,
Let's say you just have to have an variable that holds the position of your widget and interact with it according to your needs.
This position variable let's call it "oldPos".
Now inside your mouse press you update this position.
By the last but not least, you relate your "oldPos" and your mouseMove actual position and move your widget.
Wallahhhh, here we have a beautiful and simple movable widget by mouse events.
Here is the simplest example.
from PyQt5.QtWidgets import QWidget
class MyMovableWidget(QWidget):
"""WToolBar is a personalized toolbar."""
homeAction = None
oldPos = QPoint()
def __init__(self):
super().__init__()
def mousePressEvent(self, evt):
"""Select the toolbar."""
self.oldPos = evt.globalPos()
def mouseMoveEvent(self, evt):
"""Move the toolbar with mouse iteration."""
delta = QPoint(evt.globalPos() - self.oldPos)
self.move(self.x() + delta.x(), self.y() + delta.y())
self.oldPos = evt.globalPos()
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
coolWidget = MyMovableWidget()
coolWidget.show()
sys.exit(app.exec_())
So simple isn't it? :D
I managed to make it work, thanks to #bnaecker for telling me that the code actually creates two widgets, I've replaced some stuff in my code. Basically, just edit the code generated when you translate the .ui to .py so it would only create one widget.
The most changes happened here:
if __name__ == "__main__":
import sys
sys.excepthook = excepthook
app = QtWidgets.QApplication(sys.argv)
hGUI = QtWidgets.QWidget(flags=QtCore.Qt.FramelessWindowHint)
ui = Ui_hGUI()
ui.setupUi(hGUI)
hGUI.show()
sys.exit(app.exec_())
Edited to this:
if __name__ == "__main__":
sys.excepthook = excepthook
app = QtWidgets.QApplication(sys.argv)
hGUI = Ui_hGUI()
sys.exit(app.exec_())
Add self.show() at the end of retranslateUi(self), replace every "hGUI" in the code with "self" or delete it if it's an argument (except for controls like buttons and labels).
Here are both codes, non-working one vs. working one: https://gist.github.com/anonymous/0707b4fef11ae4b31cf56dc78dd3af80
Note: In the new code, the app is called "VirtualMemories".

How to remember last geometry of PyQt application?

I am using PyQt5 5.5.1 (64-bit) with Python 3.4.0 (64-bit) on Windows 8.1
64-bit.
I am having trouble restoring the position and size (geometry) of my
very simple PyQt app.
Here is minimal working application:
import sys
from PyQt5.QtWidgets import QApplication, QWidget
class myApp(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.show()
if __name__ == '__main__':
app = QApplication(sys.argv)
view = myApp()
sys.exit(app.exec())
What I read online is that this is the default behavior and we need to
use QSettings to save and retrieve settings from Windows registry,
which is stored in
\\HKEY_CURRENT_USER\Software\{CompanyName}\{AppName}\
Here are some of the links I read.
I could have followed those tutorials but those tutorials/docs were
written for C++ users.
C++ is not my glass of beer, and converting those codes are impossible to me.
Related:
QSettings(): How to save to current working directory
This should do.
import sys
from PyQt5.QtWidgets import QApplication, QWidget
from PyQt5.QtCore import QSettings, QPoint, QSize
class myApp(QWidget):
def __init__(self):
super(myApp, self).__init__()
self.settings = QSettings( 'My company', 'myApp')
# Initial window size/pos last saved. Use default values for first time
self.resize(self.settings.value("size", QSize(270, 225)))
self.move(self.settings.value("pos", QPoint(50, 50)))
def closeEvent(self, e):
# Write window size and position to config file
self.settings.setValue("size", self.size())
self.settings.setValue("pos", self.pos())
e.accept()
if __name__ == '__main__':
app = QApplication(sys.argv)
frame = myApp()
frame.show()
app.exec_()
I simplified this example: QSettings(): How to save to current working directory
Similar to #Valentin's response, because I feel settings are being written to registry, which will be issue for cross compatiblity. Here is the relevant startEvent() and closeEvent() for the job.
def startEvent()
self.settings = QSettings(QSettings.IniFormat,QSettings.SystemScope, '__MyBiz', '__settings')
self.settings.setFallbacksEnabled(False) # File only, not registry or or.
# setPath() to try to save to current working directory
self.settings.setPath(QSettings.IniFormat,QSettings.SystemScope, './__settings.ini')
# Initial window size/pos last saved
self.resize(self.settings.value("size", QSize(270, 225)))
self.move(self.settings.value("pos", QPoint(50, 50)))
self.tab = QWidget()
def closeEvent(self, e):
# Write window size and position to config file
self.settings.setValue("size", self.size())
self.settings.setValue("pos", self.pos())
startEvent() should be initiated at startup and closeEvent() should be taken care before quitting the main window.
You should indeed use QSetting for this.
All the Qt examples have been converted to Python. They are included in the source packages of PyQt (or PySide), which you can download here
You can also look online in the github repo, particularly in application.py of mainwindows example.
def readSettings(self):
settings = QSettings("Trolltech", "Application Example")
pos = settings.value("pos", QPoint(200, 200))
size = settings.value("size", QSize(400, 400))
self.resize(size)
self.move(pos)
def writeSettings(self):
settings = QSettings("Trolltech", "Application Example")
settings.setValue("pos", self.pos())
settings.setValue("size", self.size())
Fire writeSettings() before quitting and initiate readSettings() on startup.
In my case I use .ini files to store settings (language, default user, ...). the same code works on both Debian and Windows.
An example:
from PySide.QtCore import QSettings
self.settings = QSettings('settings.ini', QSettings.IniFormat)
...
self.settings.setValue('size', self.size())

Categories