Embedding Jupyter in Qt Application - qt

I have a Qt application with an embedded Jupyter QtConsole. This is the code that I use to create the Jupyter console:
from qtconsole.rich_jupyter_widget import RichJupyterWidget
from qtconsole.inprocess import QtInProcessKernelManager
class EmbeddedJupyterConsole(RichJupyterWidget):
def __init__(self, gui):
super(RichJupyterWidget, self).__init__(gui.ipython_container)
self.kernel_manager = QtInProcessKernelManager()
self.kernel_manager.start_kernel()
self.kernel = self.kernel_manager.kernel
self.kernel.gui = 'qt4'
self.kernel_client = self.kernel_manager.client()
self.kernel_client.start_channels()
gui.ipython.kernel_manager = self.kernel_manager
gui.ipython.kernel_client = self.kernel_client
gui.ipython.exit_requested.connect(self.stop)
def executeCmd(self, cmd):
self.kernel.shell.ev(cmd)
def pushVar(self, **kwarg):
self.kernel.shell.push(kwarg)
def stop(self):
self.kernel_client.stop_channels()
self.kernel_manager.shutdown_kernel()
self.app.exit()
And this is the code that I use to generate the main Qt window:
class QtMainWindow(QMainWindow):
def __init__(self,app):
self.console = EmbeddedJupyterConsole(self)
# Initialize other widgets within the main window
if __name__ == '__main__':
import sys
app = QtGui.QApplication(sys.argv)
window = QtMainWindow(app)
sys.exit(app.exec_())
Whenever I run this code, the Jupyter console and QtApplication work correctly. However, I also see the following error:
Traceback (most recent call last):
File "C:\...\Miniconda2\lib\site-packages\qtconsole\console_widget.py", line 464, in sizeHint
font_metrics = QtGui.QFontMetrics(self.font)
AttributeError: 'EmbeddedJupyterConsole' object has no attribute 'font'
If I add add a "fake" font property to the EmbeddedJupyterConsole, then I loose the nice format of the console and the error still appears. Does anyone know what is the issue and how to solve it?

Related

How do I pass a variable to a QThread object when creating an instance? I'm getting a type error in Qthread.__init__

I found this sample code using QThread at https://doc.qt.io/qtforpython/examples/example_widgets__thread_signals.html
I modified the code in an attempt to pass a variable to the thread when instantiated based on info I found here: https://nikolak.com/pyqt-threading-tutorial/
Unfortunately I am getting the following error:
Traceback (most recent call last):
File "C:\Users\joe\python\ThreadTest.py", line 22, in start_thread
instanced_thread = WorkerThread(self, 'c:\testfile.xml')
File "C:\Users\joe\python\ThreadTest.py", line 44, in __init__
QThread.__init__(self, parent)
TypeError: 'PySide6.QtCore.QThread.__init__' called with wrong argument types:
PySide6.QtCore.QThread.__init__(str)
Supported signatures:
PySide6.QtCore.QThread.__init__(Optional[PySide6.QtCore.QObject] = None)
Can someone tell me the proper syntax for passing a variable to a QThread?
I'm using PySide6 and Python 3.9.10.
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
import sys
from PySide6.QtCore import QObject, QThread, Signal, Slot
from PySide6.QtWidgets import QApplication, QPushButton, QVBoxLayout, QWidget
# Create a basic window with a layout and a button
class MainForm(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("My Form")
self.layout = QVBoxLayout()
self.button = QPushButton("Click me!")
self.button.clicked.connect(self.start_thread)
self.layout.addWidget(self.button)
self.setLayout(self.layout)
# Instantiate and start a new thread
def start_thread(self):
instanced_thread = WorkerThread(self, 'c:\testfile.xml')
instanced_thread.start()
# Create the Slots that will receive signals
#Slot(str)
def update_str_field(self, message):
print(message)
#Slot(int)
def update_int_field(self, value):
print(value)
# Signals must inherit QObject
class MySignals(QObject):
signal_str = Signal(str)
signal_int = Signal(int)
# Create the Worker Thread
class WorkerThread(QThread):
def __init__(self, filename, parent=None):
QThread.__init__(self, parent)
# Instantiate signals and connect signals to the slots
self.signals = MySignals()
self.signals.signal_str.connect(parent.update_str_field)
self.signals.signal_int.connect(parent.update_int_field)
self.filename = filename
def run(self):
# Do something on the worker thread
a = 1 + 1
# Emit signals whenever you want
self.signals.signal_int.emit(a)
self.signals.signal_str.emit("This text comes to Main thread from our Worker thread.")
print(self.filename)
if __name__ == "__main__":
app = QApplication(sys.argv)
window = MainForm()
window.show()
sys.exit(app.exec())

Can you embed an external application in PyQt5 GUI on OSX

I'm working on an application that runs visualization using 3rd party software, and sending commands and doing other things through the PyQt5 GUI. At this point, both the PyQt5 window and the visualization run on separate windows, but I'd like to at some point merge them so that it looks like one window. To do that, I'm trying to make a simple example work. Here is code that spawns the calculator app on Mac and a simple window that has some text labels in it:
import os
import sys
import subprocess
import atexit
from PyQt5 import QtWidgets
class CalcWindow(QtWidgets.QMainWindow):
def __init__(self):
super(CalcWindow, self).__init__()
self.setWindowTitle("Embedded Calc")
lines_widget = LinesWidget()
self.setCentralWidget(lines_widget)
calc_path = "/Applications/Calculator.app/Contents/MacOS/Calculator"
print("Path = " + calc_path)
print("Exists: " + str(os.path.exists(calc_path)))
p = subprocess.Popen(calc_path)
atexit.register(self.kill_proc, p)
#staticmethod
def kill_proc(proc):
try:
proc.terminate()
except Exception:
pass
class LinesWidget(QtWidgets.QWidget):
def __init__(self):
super().__init__()
self.vLayout = QtWidgets.QVBoxLayout()
self.line1 = QtWidgets.QHBoxLayout()
self.line1.addWidget(QtWidgets.QLabel("HELLO"))
self.line1.addWidget(QtWidgets.QLabel("WORLD"))
self.line2 = QtWidgets.QHBoxLayout()
self.line2.addWidget(QtWidgets.QLabel("SUP"))
self.line2.addWidget(QtWidgets.QLabel("DAWG"))
self.vLayout.addLayout(self.line1)
self.vLayout.addLayout(self.line2)
self.setLayout(self.vLayout)
def main():
app = QtWidgets.QApplication(sys.argv)
calc = CalcWindow()
calc.show()
sys.exit(app.exec_())
if __name__ == "__main__":
main()
I'd like the calculator to be apart of the same window as the Text Labels which are in the main window. I've seen it done on the Windows using hwnd , but I don't know how to directly translate that to OSX or if it's even possible. Maybe there's some PyQt magic of throwing the executable in a widget and adding it to the main window that would work. Not sure. Any help would be appreciated. Thanks.

PyQt4 display dialog box on all displays windows 10

First off thanks for the help, I am a unix admin and don't know much about QT or windows 10
I have to display a qt popup menu/app on all displays on windows 10 using winexe to access a remote box, the behavior should be like the below winexe command:
winexe -U 'ad/user%xxxxxxx' --system --interactive=1 //10.14.6.133 'msg * hello jello'
below is my command line for the PyQt4 script:
winexe -U 'ad/user%xxxxxxx' --system --interactive=1 //10.14.6.133 'cmd /c c:\python26\python.exe c:\scripts\bobo3.py'
It just sits there and does nothing visible. My guess is it needs to be displayed to all active displays and I have no idea how to do this.
Here is the code, it works when run from a cmd prompt locally:
from optparse import OptionParser
from PyQt4 import QtGui, QtCore
class TopDialog(QtGui.QWidget):
def __init__(self, title='Message', width=960, height=640, ):
super(TopDialog, self).__init__()
self.setFixedSize(width, height)
self.setWindowFlags(QtCore.Qt.FramelessWindowHint | QtCore.Qt.WindowStaysOnTopHint)
screen = QtGui.QDesktopWidget().screenGeometry()
self.move((screen.width() - self.width())/2, (screen.height() - self.height())/2)
if not isinstance(title, unicode):
title = title.decode('utf-8')
self.title_lb = QtGui.QLabel(title)
self.title_lb.setAlignment(QtCore.Qt.AlignCenter)
self.title_lb.setFrameStyle(QtGui.QFrame.StyledPanel | QtGui.QFrame.Sunken)
self.message_lb = QtGui.QLabel()
self.message_lb.setAlignment(QtCore.Qt.AlignCenter)
self.message_lb.setMinimumSize(self.width()/2, self.height()/2)
self.ok_bt = QtGui.QPushButton('OK')
self.ok_bt.clicked.connect(self._ok_bt_clicked)
self.main_lo = QtGui.QVBoxLayout()
self.main_lo.addWidget(self.title_lb)
self.main_lo.addStretch()
self.main_lo.addWidget(self.message_lb)
self.main_lo.addStretch()
self.main_lo.addWidget(self.ok_bt)
self.setLayout(self.main_lo)
def set_message(self, message):
if not isinstance(message, unicode):
message = message.decode('utf-8')
self.message_lb.setText(message)
def set_button_text(self, text):
if not isinstance(text, unicode):
text = text.decode('utf-8')
self.ok_bt.setText(text)
def _ok_bt_clicked(self):
# do something you want.
self.close() # close the window
client = None
def main():
global client
parser = OptionParser()
parser.add_option('-m', '--message', type=str, action="store", dest="message", help="The alert message")
parser.add_option('-s', '--sent_by', type=str, action="store", dest="sent_by", help='login of sender')
(options, args) = parser.parse_args()
app = QtGui.QApplication(sys.argv)
sent_by = options.sent_by
if sent_by is None:
sent_by = "Someone"
message = options.message
if message is None:
message = "we are not sure why"
print sent_by, message
client = TopDialog(' %s wants your attention' % (sent_by))
client.set_message('%s' % (message))
client.set_button_text('OK')
client.show()
app.exec_()
main()

PyQt4: How to load compiled ui-files correctly?

I created a Qt resource file with all my ui files inside of it, I compiled that with pyrcc4 command-line in a python file, and then I loaded the ui files using loadUi. Here an example:
#!/usr/bin/env python
#-*- coding:utf-8 -*-
import os
import sys
from PyQt4.QtCore import Qt, QFile
from PyQt4.uic import loadUi
from PyQt4.QtGui import QDialog
from xarphus.gui import ui_rc
# I import the compiled qt resource file named ui_rc
BASE_PATH = os.path.dirname(os.path.abspath(__file__))
#UI_PATH = os.path.join(BASE_PATH, 'gui', 'create_user.ui')
UI_PATH = QFile(":/ui_file/create_user.ui")
# I want to load those compiled ui files,
# so I just create QFile.
class CreateUser_Window(QDialog):
def __init__(self, parent):
QDialog.__init__(self, parent)
# I open the created QFile
UI_PATH.open(QFile.ReadOnly)
# I read the QFile and load the ui file
self.ui_create_user = loadUi(UI_PATH, self)
# After then I close it
UI_PATH.close()
Well its works fine, but I have a problem. When I open the GUI-window once, everything works fine. After closing the window I try to open the same GUI-window again, I get ja long traceback.
Traceback (most recent call last): File "D:\Dan\Python\xarphus\xarphus\frm_mdi.py", line 359, in
create_update_form self.update_form = Update_Window(self) File
"D:\Dan\Python\xarphus\xarphus\frm_update.py", line 135, in init
self.ui_update = loadUi(UI_PATH, self) File
"C:\Python27\lib\site-packages\PyQt4\uic__init__.py", line 238, in
loadUi return DynamicUILoader(package).loadUi(uifile, baseinstance,
resource_suffix) File
"C:\Python27\lib\site-packages\PyQt4\uic\Loader\loader.py", line 71,
in loadUi return self.parse(filename, resource_suffix, basedir) File
"C:\Python27\lib\site-packages\PyQt4\uic\uiparser.py", line 984, in
parse document = parse(filename) File
"C:\Python27\lib\xml\etree\ElementTree.py", line 1182, in parse
tree.parse(source, parser) File
"C:\Python27\lib\xml\etree\ElementTree.py", line 657, in parse
self._root = parser.close() File
"C:\Python27\lib\xml\etree\ElementTree.py", line 1654, in close
self._raiseerror(v) File "C:\Python27\lib\xml\etree\ElementTree.py",
line 1506, in _raiseerror raise err xml.etree.ElementTree.ParseError:
no element found: line 1, column 0
Can everyone help me?
Maybe I have a solution, but I don't know if that is a perfectly pythonic.
Well, we know all python projects have an __ init __-file. We need it for initializing Python packages, right? Well I thought: Why not use this file? What did I do? I define in the __ init __ -file a function like so:
#!/usr/bin/env python
#-*- coding:utf-8 -*-
from PyQt4.uic import loadUi
from PyQt4.QtCore import Qt, QFile
def ui_load_about(self):
uiFile = QFile(":/ui_file/about.ui")
uiFile.open(QFile.ReadOnly)
self.ui_about = loadUi(uiFile)
uiFile.close()
return self.ui_about
Now in my "About_Window"-class I do this:
#!/usr/bin/env python
#-*- coding:utf-8 -*-
import os
import sys
from PyQt4.QtCore import Qt, QFile
from PyQt4.uic import loadUi
from PyQt4.QtGui import QDialog
import __init__ as ui_file
class About_Window(QDialog):
def __init__(self, parent):
QDialog.__init__(self, parent)
self.ui_about = ui_file.ui_load_about(self)
You see I importe the package-file (__ init __-file) as ui_file and then I call the function and save the return of the function in the variable self.ui_about.
In my case I open the About_Window from a MainWindow(QMainWindow), and it looks like so:
def create_about_form(self):
self.ui_about = About_Window(self)
# Now when I try to show (show()-method) a window I get two windows
# The reason is: I open and load the ui files from compiled
# qt resorce file that was define in __init__-module.
# There is a function that opens the resource file, reads
# the ui file an closes and returns the ui file back
# That's the reason why I have commented out this method
#self.ui_about.show()
You see I commented out the show()-method. It works without this method. I only define the About_Window()-class. Well I know that isn't maybe the best solution, but it works. I can open the window again and again without traceback.
If you have a better solution or idea let me know :-)

PyQt5 file dialog not showing up

I have connected a QPushButton to a method that call file dialog. The simplified code look like this:
def init_buttons(self):
self.browse_button = QPushButton('&Browse')
self.browse_button.clicked.connect(self.browse_file)
def browse_file(self):
file_name = QFileDialog.getExistingDirectory()
# Just for checking
print(file_name)
Sometimes QFileDialog won't showing up. The process is indeed running, since the main class/widget doesn't response to my clicking. Sometimes it's showing up.
If QFileDialog doesn't show up, with pycharm, I have to stop and kill process to end the program. If I run the program directly from terminal, I have to manually end the running process to end the program. I can't figure out what causing this, since terminal not showing any exception or warning.
So, what is this?
The parameters for the getExistingDirectory were wrong. Please try this. Also, I have added further information in my pull request.
import os
def browse_file(self):
self.save_dir = QFileDialog.getExistingDirectory(self,
"Open Save Directory", os.path.expanduser('~'))
print(self.save_dir)
#!/usr/bin/python3
# -*- coding: utf-8 -*-
import sys
from PyQt5.QtWidgets import (QMainWindow, QTextEdit,
QAction,QMessageBox, QFileDialog, QApplication,QPushButton,QInputDialog,QLineEdit)
from PyQt5.QtGui import QIcon
class Example(QMainWindow):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.fileName=""
self.text=""
btn1 = QPushButton("Encrypt", self)
btn1.clicked.connect(self.onBtn1)
self.show()
def onBtn1(self):
self.fileName, _ = QFileDialog.getOpenFileName(self, 'Open file', '/Users/Jarvis/Desktop/')
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())

Resources