How to bring PyQt QProcess window to front? - python-3.x

I am starting a QProcess and would like to bring the resulting window on top everytime a command is written to QProcess.
However, if my process is "gnuplot.exe" (Win7) the plot window will be updated but always stays behind the PyQt window. I haven't yet found a way to bring it to front, or make it active, or put the focus on, or however you would call it.
Something like
self.process. ...
raise(), show(), activateWindow(), SetForegroundWindow, WindowStaysOnTopHint ... ???
These posts didn't help me further
How to find the active PyQt window and bring it to the front
https://forum.qt.io/topic/30018/solved-bring-to-front-window-application-managed-with-qprocess/3
Bring QProcess window to front (running Qt Assistant)
Here is the code:
import sys
from PyQt5.QtCore import QProcess, pyqtSlot
from PyQt5.QtWidgets import QApplication, QWidget, QPushButton
import subprocess
class MyWindow(QWidget):
def __init__(self):
super(MyWindow,self).__init__()
self.setGeometry(100,100,500,500)
self.button1 = QPushButton('New plot',self)
self.button1.clicked.connect(self.button1_clicked)
self.process = QProcess(self)
self.process.start(r'C:\Programs\gnuplot\bin\gnuplot.exe', ["-p"])
self.n = 1
def button1_clicked(self):
plotcmd = "plot x**"+str(self.n)+"\n"
self.process.write(plotcmd.encode())
self.n += 1
response = self.process.readAllStandardOutput()
print(str(response, encoding="utf-8"))
if __name__ == '__main__':
app = QApplication(sys.argv)
app.setStyle("plastique")
window = MyWindow()
window.show()
sys.exit(app.exec_())

Based on the comment and links from #buck54321, I got to the following version which seems to (almost) work.
The solution in the above links seem to be more general and a bit too complicated for my case, since I know the exact name of my window which I want to bring to front.
To my original code I just had to add three lines. I was not familiar with win32gui.
However, with my code, only after the button is pressed the second time the window will be brought to front. After the first button press hwnd is still 0 which leads to a crash. I guess this is because gnuplot.exe will start without opening a window, and opens a window only after the first command has been sent.
If anybody can show me how to bring the window to front even after the first button click that would be great.
If there are limitation or improvements I would be happy to learn about them.
Here is the code:
import sys
from PyQt5.QtCore import QProcess, pyqtSlot
from PyQt5.QtWidgets import QApplication, QWidget, QPushButton
import subprocess
import win32gui ####### new line
class MyWindow(QWidget):
def __init__(self):
super(MyWindow,self).__init__()
self.setGeometry(100,100,500,500)
self.button1 = QPushButton('New plot',self)
self.button1.clicked.connect(self.button1_clicked)
self.process = QProcess(self)
self.process.start(r'C:\Programs\gnuplot\bin\gnuplot.exe', ["-p"])
self.n = 1
def button1_clicked(self):
plotcmd = "set term wxt 999\n plot x**"+str(self.n)+"\n"
self.process.write(plotcmd.encode())
self.n += 1
hwnd = win32gui.FindWindow(None, "Gnuplot (window id : 999)") ####### new line
response = self.process.readAllStandardOutput()
print(str(response, encoding="utf-8"))
if hwnd != 0: win32gui.SetForegroundWindow(hwnd) ####### new line
if __name__ == '__main__':
app = QApplication(sys.argv)
app.setStyle("plastique")
window = MyWindow()
window.show()
sys.exit(app.exec_())

Related

QMainWindow mouseDoubleClickEvent override not working

I'm using the below code to try and capture double clicks within the main window"
import sys
from PySide6 import QtCore
from PySide6.QtWidgets import (
QApplication,
QGridLayout,
QMainWindow,
QSplitter,
QTreeView,
QWidget,
)
from PySide6.QtWebEngineWidgets import QWebEngineView
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.windowLayout = QGridLayout()
self.splitter = QSplitter()
self.webView = QWebEngineView()
self.webView.setUrl(QtCore.QUrl("http://127.0.0.1:8080"))
self.tree = QTreeView()
self.splitter.addWidget(self.webView)
self.splitter.addWidget(self.tree)
self.windowLayout.addWidget(self.splitter)
self.mainWidget = QWidget()
self.mainWidget.setLayout(self.windowLayout)
self.setCentralWidget(self.mainWidget)
def mouseDoubleClickEvent(self, e):
print('test')
if __name__ == "__main__":
app = QApplication(sys.argv)
window = MainWindow()
window.resize(1500, 1000)
window.show()
app.exec()
And I get the following console output:
qt.pointer.dispatch: delivering touch release to same window QWindow(0x0) not QWidgetWindow(0x600003bb8e40, name="MainWindowClassWindow")
qt.pointer.dispatch: skipping QEventPoint(id=1 ts=0 pos=0,0 scn=749.346,451.159 gbl=749.346,451.159 Released ellipse=(1x1 ∡ 0) vel=0,0 press=-749.346,-451.159 last=-749.346,-451.159 Δ 749.346,451.159) : no target window
however, when I comment out self.setCentralWidget(self.mainWidget) I obviously don't see anything, but the double click triggers. Any suggestions?
EDIT: update to min repro, also note that clicking anywhere not inside the QWebEngineView correctly results in mouseDoubleClickEvent triggering. However, the above error results when I click in the QWebEngineView, and nothing happens when I click inside the QTreeView
As per musicamante's very useful comments (see original post), the solution I ended up using was
...
self.tree.doubleClicked.connect(self.treeDoubleClicked)
...
def treeDoubleClicked(self, index):
self.selectedFilepath = index.model().filePath(index)

Entering fullscreen mode hides the icon from taskbar and the application runs from background

When I made a window go into fullscreen mode, the application icon was hidden from the taskbar (after doing alt-tab). It also didn't appear in the alt+tab windows. It only showed the other windows that I had open.
When I checked task manager, the python process was under the background processes category. I couldn't switch back to the window.
How can I stop the application from running in the background when I enter fullscreen mode?
My code:
import sys
from PyQt5.QtGui import QKeySequence
from PyQt5.QtWidgets import QApplication, QLabel, QMainWindow, QShortcut
from PyQt5.QtCore import Qt
# Subclass QMainWindow to customise your application's main window
class MainWindow(QMainWindow):
def __init__(self, *args, **kwargs):
super(MainWindow, self).__init__(*args, **kwargs)
self.setWindowTitle("Hello fullscreen world")
label = QLabel("Hello fullscreen world")
# The `Qt` namespace has a lot of attributes to customise
# widgets. See: http://doc.qt.io/qt-5/qt.html
label.setAlignment(Qt.AlignCenter)
# Set the central widget of the Window. Widget will expand
# to take up all the space in the window by default.
self.setCentralWidget(label)
self.shortcut_close_window = QShortcut(QKeySequence('F11'), self)
self.shortcut_close_window.activated.connect(self.goFullscreen)
def goFullscreen(self):
if self.isFullScreen():
self.setWindowFlags(self._flags)
self.showNormal()
else:
self._flags = self.windowFlags()
self.setWindowFlags(Qt.WindowCloseButtonHint | Qt.WindowType_Mask)
self.showFullScreen()
app = QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec_()
Note: even terminating the process using ctrl+c or closing command prompt doesn't work, only task manager does.
I don't know why you are using self.setWindowFlags in goFullscreen() function. It is unnecessary.
def goFullscreen(self):
if self.isFullScreen():
#self.setWindowFlags(self._flags)
self.showNormal()
else:
#self._flags = self.windowFlags()
#self.setWindowFlags(Qt.WindowCloseButtonHint | Qt.WindowType_Mask)
self.showFullScreen()
Btw, the reason is that you use the Qt.WindowType_Mask flag.
WindowType_Mask: A mask for extracting the window type part of the
window flags.
~Window Flags~
I had no idea that there was such a strange bug in Ubuntu. So all you have to do is write your own FullScreen method:
(I don't use ubuntu. So I don't know if you will run into a bug again.)
import sys
from PyQt5.QtGui import QKeySequence
from PyQt5.QtWidgets import QApplication, QLabel, QMainWindow, QShortcut
from PyQt5.QtCore import Qt
# Subclass QMainWindow to customise your application's main window
class MainWindow(QMainWindow):
isfullscreen = False
def __init__(self, *args, **kwargs):
super(MainWindow, self).__init__(*args, **kwargs)
self.setWindowTitle("Hello fullscreen world")
self._flags = self.windowFlags()
self._geometry = ((self.screen().size().width() / 2) - (self.width() / 2),
(self.screen().size().height() / 2) - (self.height() / 2), 600, 400)
self.setGeometry(*self._geometry)
label = QLabel("Hello fullscreen world")
# The `Qt` namespace has a lot of attributes to customise
# widgets. See: http://doc.qt.io/qt-5/qt.html
label.setAlignment(Qt.AlignCenter)
# Set the central widget of the Window. Widget will expand
# to take up all the space in the window by default.
self.setCentralWidget(label)
self.shortcut_close_window = QShortcut(QKeySequence('F11'), self)
self.shortcut_close_window.activated.connect(self.goShowFullScreen)
self._geometry = self.geometry()
def goShowFullScreen(self):
if not self.isfullscreen:
self.setWindowFlags(Qt.WindowStaysOnTopHint | Qt.FramelessWindowHint)
self.setGeometry(self.screen().geometry())
self.show()
self.isfullscreen = True
else:
self.setWindowFlags(self.windowFlags() & ~Qt.WindowStaysOnTopHint)
self.setWindowFlags(self.windowFlags() & ~Qt.FramelessWindowHint)
self.setGeometry(self._geometry)
self.show()
self.isfullscreen = False
app = QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec_()

slot to right click menu action does does not work

I have written the below code to which I finally managed to add menu but connecitn menu to a function doesnt seem to work:
import os
from PyQt5 import uic
from PyQt5 import QtWidgets
from PyQt5 import QtCore
FILE_LOCATION = os.path.dirname(os.path.realpath(__file__))
class MainDialogWindow(QtWidgets.QDialog):
def __init__(self):
super(MainDialogWindow,self).__init__()
ui_file = os.path.join(FILE_LOCATION, "example.ui")
self._ui = uic.loadUi(ui_file, self)
self.registerCallbacks()
self.initUI()
def initUI(self):
"""Initialize the UI.
"""
self.textBrowser.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
def registerCallbacks(self):
self.textBrowser.customContextMenuRequested.connect(self.context_menu)
# self.connect(self.textBrowser, QtCore.Signal('customContextMenuRequested(const QPoint &)'), self.context_menu)
def context_menu(self, pos):
menu = QtWidgets.QMenu(self)
action = menu.addAction("clear")
menu.exec_(self.mapToGlobal(pos))
action.trigered.connect(self.clear)
def clear(self):
"""Slot to claer text.
"""
print("clear")
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
window = MainDialogWindow()
window.show()
window.setGeometry(500, 300, 300, 300)
sys.exit(app.exec_())
please helpp,, I want call the clear function from the right click menu
I don't seem to understand how the menu.exec_() method works, that method blocks the execution of sequential tasks until the user selects a QAction from the QMenu. In your case, for example, until when you press "clear" and the triggered signal is emitted (note: you have a typo), but at that moment there is no connection, so the clear method will not be called. The solution is to make the connection before invoking the QMenu exec_():
def context_menu(self, pos):
menu = QtWidgets.QMenu(self)
action = menu.addAction("clear")
action.triggered.connect(self.clear)
menu.exec_(self.mapToGlobal(pos))

PySide2 How to unassign current layout and assign a new one to a window widget? .count() gives attribute error?

I'm new to PySide2, started using it yesterday. I'm teaching myself from the API documentation and info I find online. I'm trying to make a small app with it to teach myself. My idea for the app was using a View like model, as you go pressing on certain buttons I delete the current layout on the window and present you with an entire new one. This foments modularity as each layout wouldn't be dependent on each other but instead fully individual. (Each part of the app is broadly different and requires almost all widgets to be deleted).
However whenever I search how to delete a layout or remove all of its widgets I always encounter a piece of code like this (This is actually from a question asked 6 months ago):
def clearLayout(self, layout):
if layout is not None:
while layout.count():
item = layout.takeAt(0)
widget = item.widget()
if widget is not None:
widget.deleteLater()
else:
self.clearLayout(item.layout())
Yet when I implement something like that, even the exact same function and then call it using, self.clearLayout(self.layout) I get the following error:
File "GUI.py", line 45, in home
self.clearLayout(self.layout)
File "GUI.py", line 16, in clearLayout
while layout.count():
AttributeError: 'builtin_function_or_method' object has no attribute 'count'
I'm assuming I probably forgot to import something important, but I can't just seem to find what. Here is a list with my imports.
import sys
from PySide2.QtWidgets import QApplication, QLabel, QLineEdit, QWidget
from PySide2.QtWidgets import QDialog, QPushButton, QVBoxLayout, QLayout
I also installed PySide2 using pip install PySide2 on command line (Anaconda). Do I have to do something else?
Thank you so much, sorry post is so long, just wanted to give you the whole information from the beginning :)
EDIT:
Further testing has led me to realise I cannot use any of the virtual functions of QLayout, or its subclasses. Apparently I have to implement them myself within the code. I believe it could be this. I don't know how to implement them though. I'm going to keep trying.
EDIT 2: Some people asked for a reporducible example so here is the code that doesn't work.
import sys
from PySide2.QtWidgets import QApplication, QLabel, QLineEdit, QWidget
from PySide2.QtWidgets import QDialog, QPushButton, QVBoxLayout, QLayout
class Window(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("Program")
self.setGeometry(300, 300, 300, 300)
self.start()
def clearLayout(self, layout):
if layout is not None:
while layout.count():
item = layout.takeAt(0)
widget = item.widget()
if widget is not None:
widget.deleteLater()
else:
self.clearLayout(item.layout())
def start(self):
self.startbutton = QPushButton("Start App")
layout = QVBoxLayout()
layout.addWidget(self.startbutton)
self.setLayout(layout)
self.startbutton.clicked.connect(self.home)
def home(self):
self.clearLayout(self.layout)
self.message=QLabel("Welcome to homepage")
layout=QVBoxLayout()
layout.addWidget(self.message)
self.setLayout(layout)
if __name__ == "__main__":
app = QApplication([])
window=Window()
window.show()
sys.exit(app.exec_())

pyqt5 can not close a topmost fullscreen qdialog on mac osx

I am writing an app that can take a screenshot on osx 10.9.5 using pyqt5; code sample is like this:
import sys
from PyQt5 import QtWidgets,QtCore,Qt
from PyQt5.Qt import QApplication
class CScreenshot(QtWidgets.QDialog):
def __init__(self):
super(CScreenshot,self).__init__()
self.setWindowFlags(QtCore.Qt.WindowStaysOnTopHint) #1
def screenshot(self):
#grab screen and paint into this dialog
#so user can modify the pix through this dialog
_screen = Qt.QApplication.primaryScreen()
self.m_snapPix = _screen.grabWindow(0)
#...
self.showFullScreen()
self.exec_()
def drawLine(_p1,_p2):
pass
#...
class CMainWindow(QtWidgets.QWidget):
def __init__(self):
super(CMainWindow,self).__init__()
self.m_btnScreenshot = QtWidgets.QPushButton(self)
self.m_btnScreenshot.clicked.connect(self.onBtnClk)
def onBtnClk(self):
ss = CScreenshot()
ss.screenshot() #here into the CScreenshot's message loop
#process next step balabala...
if __name__ == "__main__":
app = QApplication(sys.argv)
w = CMainWindow()
w.show()
sys.exit(app.exec_())
Here comes the question: When I click the button, the fullscreen dialog pops up and stays on topmost, everything works fine. But when I press the Esc button, the dialog should close and show the main window, but the screen just fixed by a black fullscreen window, which has the title python. If I remove the #1 marked line, it will work fine, but I need the dialog to stay topmost, hope someone can help me to figure out the problem.
I read the doc,and found the answer:"To return from full-screen mode,call showNormal()".It's my stupid.

Resources