I have been building an application in Python 3.10 and PyQt6. This application has 3 parts: A main window that has a grid of buttons, a settings window that settings which change depending on the button clicked, and a window where a task is run using those settings.
The application works 100% in PyCharm. When packaged using PyInstaller 5.0.1, the main and settings windows load fine. In the settings, I have a button to launch a QFileDialog so the user can select a directory. However, for half of the settings windows, when the user either hits "Cancel" or selects a directory, the entire program crashes. For the other half, everything works as intended (the selected directory is stored as a string). The specific windows that fail or don't never change.
The function to open the QFileDialog, the button to launch that function, and the class variable where the string is store are all part of the parent class. I have included a snippet below that has my general structure: A settings class (which is in settings.py) and two children of that class, DdSettings and PdSettings, which inherit from it (and are in discount.py). All of the code is public on my GitHub too.
class Settings(QWidget):
def __init__(self, task):
super().__init__()
# Window title
self.setWindowFlags(Qt.WindowType.FramelessWindowHint)
# setting the geometry of window
self.setGeometry(0, 0, 700, 400)
# Default directory
self.wd = 'No directory selected'
# Make overarching layout
self.over_layout = QVBoxLayout()
# Make a label with instructions
self.header = QLabel('Enter the appropriate values:', self)
self.header.setFont(QFont('Helvetica', 30))
self.header.setAlignment(Qt.AlignmentFlag.AlignCenter)
# Add header to overarching layout
self.over_layout.addWidget(self.header)
# Make form layout for all the settingsguis
self.layout = QFormLayout()
# ID
self.idform = QLineEdit()
self.idform.setText('9999')
self.layout.addRow(QLabel('Subject ID:'), self.idform)
# Session form
self.sessionin = QLineEdit()
self.sessionin.setText('Pretest')
self.layout.addRow(QLabel('Session name/number (enter \"Practice\" to not have output):'), self.sessionin)
# WD input
self.wdset = QPushButton('Select Directory')
self.wdset.clicked.connect(self.fileselect)
self.wdlabel = QLabel(self.wd)
# Submit button
self.submit = QPushButton('Submit')
self.submit.clicked.connect(self.checksettings)
# Quit button
self.quitbutton = QPushButton('Quit')
self.quitbutton.clicked.connect(QApplication.instance().quit)
self.quitbutton.resize(self.quitbutton.sizeHint())
# Add in elements
self.elements()
# Show all elements
self.show()
def fileselect(self):
"""
This function creates a dialog window to select a directory that will be the output directoty and then sets
the class variable (and associated QLabel) for the working directory to the directory you chose
"""
folder = QFileDialog.getExistingDirectory(self, 'Select Directory')
self.wd = str(folder)
self.wdlabel.setText(self.wd)
# This works
class DdSettings(settings.Settings):
def __init__(self, task):
super().__init__(task)
def elements(self):
# Make form layout for all the settingsguis
self.layout.addRow(QLabel('Current output directory:'), self.wdlabel)
self.layout.addRow(QLabel('Click to choose where to save your output:'), self.wdset)
self.layout.addRow(self.quitbutton, self.submit)
# Add form layout to overarching layout
self.over_layout.addLayout(self.layout)
self.setLayout(self.over_layout)
# This does not work
class PdSettings(settings.Settings):
def __init__(self, task):
super().__init__(task)
def elements(self):
self.layout.addRow(QLabel('Current output directory:'), self.wdlabel)
self.layout.addRow(QLabel('Click to choose where to save your output:'), self.wdset)
self.layout.addRow(self.quitbutton, self.submit)
# Add form layout to overarching layout
self.over_layout.addLayout(self.layout)
self.setLayout(self.over_layout)
Nothing is changed from the parent, and this only crashes when the application is packaged. No error messages are thrown when I run the executable in the console window, so I have no idea how I can provide error messages for insight.
Related
I successfully created a second window (ChiffrerWindow) but whenever I try to click a button in the second window nothing happens (The button don't execute the slots). They behave like blank widgets
I have 5 files ui_mainwindow.py and ui_chiffrerwindow.py (Which are generated from QtDesigner), chiffrerwindow.py and mainwindow.py (Are the corresponding files where I pass in the slots),
main.py (Executes the app).
This is my mainwindow.py (I didn't show the top file imports)
from ui_mainwindow import Ui_MainWindow
from ui_chiffrerwindow import Ui_ChiffrerWindow
class MainWindow(QMainWindow, Ui_MainWindow,Ui_ChiffrerWindow):
def __init__(self,app):
super().__init__()
self.setupUi(self)
self.actionChiffrer.triggered.connect(self.ouvrirChiffrer)
def ouvrirChiffrer(self):
self.window = QtWidgets.QMainWindow()
self.ui = Ui_ChiffrerWindow()
self.ui.setupUi(self.window)
self.window.show()
This is my chiffrerwindow.py
from ui_chiffrerwindow import Ui_ChiffrerWindow
class ChiffrerWindow(QMainWindow, Ui_ChiffrerWindow):
def __init__(self,app):
super().__init__()
self.setupUi(self)
self.ui = Ui_ChiffrerWindow()
# self.getFileToEncrypt = self.findChild(QPushButton, "pushButtonFileDirCrypt")
# self.getPubKeyToEncrypt = self.findChild(QPushButton, "pushButtonPubKeyCrypt")
# self.line_edit_file_dir = self.findChild(QLineEdit, "lineEditFileDirCrypt")
# self.ine_edit_pub_key = self.findChild(QLineEdit, "lineEditPubKeyCrypt")
self.ui.pushButtonFileDirCrypt.clicked.connect(self.getFileToEncrypt)
self.ui.pushButtonPubKeyCrypt.clicked.connect(self.getPubKeyToEncrypt)
def getFileToEncrypt(self):
fname = QFileDialog.getOpenFileName(self,"Open File","", "All Files (*);; Word Documents (*.docx)")
# Output file name
if fname:
self.ui.lineEditFileDirCrypt.setText(fname[0])
def getPubKeyToEncrypt(self):
print("You want to get the keys to encrypt the file")
This is what my app looks like. This is the main window
This is the main window
This is the second window
This is the second window. Whenever I click the buttons on the second window I would like to open a File Dialog to permit to the user to select a file.
I am a beginner and this is a project of implementing PGP cryptography in a desktop app.
Thank you very much for your concern and your help
I am building a PyQt application which is supposed to receive mouse right-click drags on a QGraphicsView, draw a "lasso" (a line stretching from the drag origin to the mouse position, and a circle at the mouse position), and then, on mouse release, erase the lasso graphics and display an input dialog for the next part of the app.
For some reason, when I use the mouse to click "Ok" on the input dialog, a menu artifact appears on the QGraphicsView which contained the lasso. The menu artifact is a drop-down menu line that says "(check mark) Exit". Occasionally it may be the context menu for one of my custom QGraphicsObjects as well - but for whatever reason, calling the dialog and then clicking "Ok" results in an unintended right-click-like event on the QGraphicsView.
This only seems to happen when the last step before method return is the QInputDialog - replacing it with a pass or a call to some other method does not result in the artifact. I'd be very grateful to anyone with a clue to what is causing this problem!
Here's the minimal code:
import sys
from PyQt4 import QtCore, QtGui
class Window(QtGui.QMainWindow):
# The app main window.
def __init__(self):
super(Window, self).__init__()
# Initialize window UI
self.initUI()
def initUI(self, labelText=None):
# Set user-interface attributes.
# Set up menu-, tool-, status-bars and add associated actions.
self.toolbar = self.addToolBar('Exit')
# Create a menu item to exit the app.
exitAction = QtGui.QAction(QtGui.QIcon('icons/exit.png'), '&Exit', self)
exitAction.triggered.connect(QtGui.qApp.quit)
self.toolbar.addAction(exitAction)
# Create the main view.
self.viewNetwork = NetworkPortal()
self.viewNetwork.setMinimumWidth(800)
self.viewNetwork.setMinimumHeight(800)
self.setCentralWidget(self.viewNetwork)
self.show()
class NetworkPortal(QtGui.QGraphicsView):
# A view which allows you to see and manipulate a network of nodes.
def __init__(self):
super(NetworkPortal, self).__init__(QtGui.QGraphicsScene())
# Add the CircleThing graphic to the scene.
circleThing = CircleThing()
self.scene().addItem(circleThing)
class CircleThing(QtGui.QGraphicsEllipseItem):
# Defines the graphical object.
def __init__(self):
super(CircleThing, self).__init__(-10, -10, 20, 20)
# Set flags for the graphical object.
self.setFlags(
QtGui.QGraphicsItem.ItemIsSelectable |
QtGui.QGraphicsItem.ItemIsMovable |
QtGui.QGraphicsItem.ItemSendsScenePositionChanges
)
self.dragLine = None
self.dragCircle = None
def mouseMoveEvent(self, event):
# Reimplements mouseMoveEvent to drag out a line which can, on
# mouseReleaseEvent, form a new Relationship or create a new Thing.
# If just beginning a drag,
if self.dragLine == None:
# Create a new lasso line.
self.startPosX = event.scenePos().x()
self.startPosY = event.scenePos().y()
self.dragLine = self.scene().addLine(
self.startPosX,
self.startPosY,
event.scenePos().x(),
event.scenePos().y(),
QtGui.QPen(QtCore.Qt.black, 1, QtCore.Qt.SolidLine)
)
# Create a new lasso circle at the location of the drag position.
self.dragCircle = QtGui.QGraphicsEllipseItem(-5, -5, 10, 10)
self.dragCircle.setPos(event.scenePos().x(),
event.scenePos().y())
self.scene().addItem(self.dragCircle)
# If a drag is already in progress,
else:
# Move the lasso line and circle to the drag position.
self.dragLine.setLine(QtCore.QLineF(self.startPosX,
self.startPosY,
event.scenePos().x(),
event.scenePos().y()))
self.dragCircle.setPos(event.scenePos().x(),
event.scenePos().y())
def mouseReleaseEvent(self, event):
# If the line already exists,
if self.dragLine != None:
# If the released button was the right mouse button,
if event.button() == QtCore.Qt.RightButton:
# Clean up the link-drag graphics.
self.scene().removeItem(self.dragLine)
self.dragLine = None
self.scene().removeItem(self.dragCircle)
self.dragCircle = None
# Create the related Thing.
# Display input box querying for name value.
entry, ok = QtGui.QInputDialog.getText(None, 'Enter some info: ',
'Input:', QtGui.QLineEdit.Normal, '')
return
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
newWindow = Window()
sys.exit(app.exec_())
This is a guess on my part, but I've seen this kind of weird thing before.
Some Qt widgets have default behavior on certain types of events. I've never used QGraphicsView, but often the default for a right click is to open a context-sensitive pop-up menu (usually useless, in my experience). That may be happening in your case, which would explain why you only see this when there's a right click.
You can suppress the default Qt behavior by calling event.ignore() before returning from mouseReleaseEvent.
There was not a direct answer to the cause of this bug, but using a QTimer.singleShot() to call the dialog (in combination with a QSignalMapper in order to enter parameters) is a functional workaround that separates the dialog from the method in which the bug was occurring. Thanks to #Avaris for this one.
I have an application which has a main window, which can have multiple subwindows. I would like to have one set of QActions in the main window that interact with the currently selected window. For example, the application might be a text editor, and clicking file->save should save the text file the user is currently working on. Additionally, some QActions are checkable, so their checked state should reflect the state of the currently active window.
Here is a minimum working example that has the basic functionality I want, but I suspect there is a better way to do it (further discussion below the code).
import sys
import PyQt4.QtGui as QtGui
class DisplayWindow(QtGui.QWidget):
def __init__(self, parent=None, name="Main Window"):
# run the initializer of the class inherited from
super(DisplayWindow, self).__init__()
self.myLayout = QtGui.QFormLayout()
self.FooLabel = QtGui.QLabel(self)
self.FooLabel.setText(name)
self.myLayout.addWidget(self.FooLabel)
self.setLayout(self.myLayout)
self.is_foo = False
def toggle_foo(self):
self.is_foo = not self.is_foo
if self.is_foo:
self.FooLabel.setText('foo')
else:
self.FooLabel.setText('bar')
class WindowActionMain(QtGui.QMainWindow):
def __init__(self):
super(WindowActionMain, self).__init__()
self.fooAction = QtGui.QAction('Foo', self)
self.fooAction.triggered.connect(self.set_foo)
self.fooAction.setCheckable(True)
menubar = self.menuBar()
fileMenu = menubar.addMenu('&File')
fileMenu.addAction(self.fooAction)
self.toolbar = self.addToolBar('File')
self.toolbar.addAction(self.fooAction)
self.centralZone = QtGui.QMdiArea()
self.centralZone.subWindowActivated.connect(
self.update_current_window)
self.setCentralWidget(self.centralZone)
self.create_dw("Window 1")
self.create_dw("Window 2")
def create_dw(self, name):
dw = DisplayWindow(name=name)
self.centralZone.addSubWindow(dw)
dw.show()
def update_current_window(self):
""" redirect future actions to affect the newly selected window,
and update checked statuses to reflect state of selected window"""
current_window = self.centralZone.activeSubWindow()
if current_window:
self.current_dw = self.centralZone.activeSubWindow().widget()
self.fooAction.setChecked(self.current_dw.is_foo)
def set_foo(self):
self.current_dw.toggle_foo()
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
ex = WindowActionMain()
ex.show()
sys.exit(app.exec_())
My actual version of DisplayWindow could be useful in many different projects, and I want to package it up so that you don't have to add a lot of code to the main window to use it. Therefore, DisplayWindow, all of its functionality and a list of available actions should be in one module, which would be imported in WindowActionMain's module. I should then be able to add more actions for DisplayWindow without changing any code in WindowActionMain. In particular, I don't want to have to write a little function like WindowActionMain.set_foo(self) just to redirect each action to the right place.
Yes, this is possible by handling the QMenu's aboutToShow signal
and considering the QGuiApplication's focusWindow (or however you get that in Qt4).
Example below shows a generic 'Window' menu acting on the frontmost window.
http://doc.qt.io/qt-4.8/qmenu.html#aboutToShow
http://doc.qt.io/qt-5/qguiapplication.html#focusWindow
def on_windowMenu_aboutToShow(self):
self.windowMenu.clear()
self.newWindowAction = QtWidgets.QAction(self)
self.newWindowAction.setShortcut("Ctrl+n")
self.newWindowAction.triggered.connect(self.on_newWindowAction)
self.newWindowAction.setText("New Window")
self.windowMenu.addAction(self.newWindowAction)
self.windowMenu.addSeparator()
playerWindows = [w for w in self.topLevelWindows() if w.type()==QtCore.Qt.Window and w.isVisible()]
for i, w in enumerate(playerWindows):
def action(i,w):
a = QtWidgets.QAction(self)
a.setText("Show Window {num} - {title}".format(num=i+1, title=w.title()))
a.triggered.connect(lambda : w.requestActivate())
a.triggered.connect(lambda : w.raise_())
self.windowMenu.addAction(a)
action(i,w)
self.windowMenu.addSeparator()
self.closeWindowAction = QtWidgets.QAction(self)
self.closeWindowAction.setShortcut("Ctrl+w")
self.closeWindowAction.triggered.connect(lambda : self.focusWindow().close())
self.closeWindowAction.setText("Close")
self.windowMenu.addAction(self.closeWindowAction)
This is a simplification of an application I wrote.
The application's main window has a button and a checkbox.
The checkbox resides inside a QScrollArea (via a widget).
The checkbox has a number stating how many times that checkbox was created.
Clicking on the button will open a dialog with a refresh button.
Clicking on the refresh button will set a new widget to the scroll area with a new checkbox.
The checkbox has a context menu that opens the same dialog.
However, when the widget is created using the dialog triggered by the context menu of the checkbox the application crashes with the following error:
2016-08-03 09:22:00.036 Python[17690:408202] modalSession has been
exited prematurely - check for a reentrant call to endModalSession:
Python(17690,0x7fff76dcb300) malloc: * error for object
0x7fff5fbfe2c0: pointer being freed was not allocated
* set a breakpoint in malloc_error_break to debug
The crash doesn't happen when clicking on the button to open the dialog and clicking refresh from the dialog.
The crash happens on both Mac and Windows.
I am using Python 2.7.10 with PySide 1.2.4
#!/usr/bin/env python
import sys
from itertools import count
from PySide import QtCore, QtGui
class MainWindow(QtGui.QMainWindow):
def __init__(self, *args, **kwargs):
super(MainWindow, self).__init__(*args, **kwargs)
self.centralwidget = QtGui.QWidget(parent=self)
self.open_diag_btn = QtGui.QPushButton('Open dialog', parent=self)
self.open_diag_btn.clicked.connect(self.open_dialog)
self.scroll_widget = QtGui.QScrollArea(parent=self)
layout = QtGui.QGridLayout(self.centralwidget)
layout.addWidget(self.scroll_widget)
layout.addWidget(self.open_diag_btn)
self.setCentralWidget(self.centralwidget)
self.set_scroll_widget()
def open_dialog(self):
dialog = Dialog(parent=self)
dialog.refresh.connect(self.set_scroll_widget) # Connecting the signal from the dialog to set a new widget to the scroll area
dialog.exec_()
# Even if I call the function here, after the dialog was closed instead of using the signal above the application crashes, but only via the checkbox
# self.set_scroll_widget()
def set_scroll_widget(self):
"""Replacing the widget of the scroll area with a new one.
The checkbox in the layout of the widget has an class instance counter so you can see how many times the checkbox was created."""
widget = QtGui.QWidget()
layout = QtGui.QVBoxLayout(widget)
widget.setLayout(layout)
open_diag_check = RefreshCheckbox(parent=self)
open_diag_check.do_open_dialog.connect(self.open_dialog) # Connecting the signal to open the dialog window
layout.addWidget(open_diag_check)
self.scroll_widget.setWidget(widget)
class RefreshCheckbox(QtGui.QCheckBox):
"""A checkbox class that has a context menu item which emits a signal that eventually opens a dialog window"""
do_open_dialog = QtCore.Signal()
_instance_counter = count(1)
def __init__(self, *args, **kwargs):
super(RefreshCheckbox, self).__init__(unicode(self._instance_counter.next()), *args, **kwargs)
self.setContextMenuPolicy(QtCore.Qt.ActionsContextMenu)
action = QtGui.QAction(self)
action.setText("Open dialog")
action.triggered.connect(self.emit_open_dialog)
self.addAction(action)
def emit_open_dialog(self):
self.do_open_dialog.emit()
class Dialog(QtGui.QDialog):
"""A dialog window with a button that emits a refresh signal when clicked.
This signal is used to call MainWindow.set_scroll_widget()"""
refresh = QtCore.Signal()
def __init__(self, *args, **kwargs):
super(Dialog, self).__init__(*args, **kwargs)
self.refresh_btn = QtGui.QPushButton('Refresh')
self.refresh_btn.clicked.connect(self.do_refresh)
layout = QtGui.QVBoxLayout(self)
layout.addWidget(self.refresh_btn)
def do_refresh(self):
self.refresh.emit()
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
mySW = MainWindow()
mySW.show()
mySW.raise_()
app.exec_()
It looks like Python is trying to delete an object (or one of its child objects) which is no longer there - but quite what causes that to happen is not completely clear to me. The problematic object is the widget set on the scroll-area. If you excplicitly keep a reference to it:
def set_scroll_widget(self):
self._old_widget = self.scroll_widget.takeWidget()
...
your example will no longer dump core.
I think running the dialog with exec may somehow be the proximal cause of the problem, since this means it will run with its own event-loop (which might have an affect on the order of deletion-related events). I was able to find a better fix for your example by running the dialog with show:
def open_dialog(self):
dialog = Dialog(parent=self)
dialog.setAttribute(QtCore.Qt.WA_DeleteOnClose)
dialog.refresh.connect(self.set_scroll_widget)
dialog.setModal(True)
dialog.show()
Doing things this way means it's no longer necessary to keep an explicit reference to the previous scroll-area widget.
I'm creating some dialogs using TkInter and need to be able to open a child sub-window (modal or modeless) on clicking a button in the parent. The child would then allow a data record to be created and this data (either the record or if the operation was cancelled) needs to be communicated back to the parent window. So far I have:
import sel_company_dlg
from Tkinter import Tk
def main():
root = Tk()
myCmp = sel_company_dlg.SelCompanyDlg(root)
root.mainloop()
if __name__ == '__main__':
main()
This invokes the top level dialog which allows the user to select a company. The company selection dialog looks like this:
class SelCompanyDlg(Frame):
def __init__(self, parent):
Frame.__init__(self, parent)
self.parent_ = parent
self.frame_ = Frame( self.parent_ )
// .. more init stuff ..
self.btNew_ = Button( self.frame_, text="New ...", command=self.onNew )
def onNew(self):
root = Toplevel()
myCmp = company_dlg.CompanyDlg(root)
On clicking the New ... button, a Create Company dialog is displayed which allows the user to fill in company details and click on create or cancel. Here's the opening bit of that:
class CompanyDlg(Frame):
def __init__(self, parent):
Frame.__init__(self, parent)
// etc.
I'm struggling with the best way of invoking the child dialog in onNew() - what I have works but I'm not convinced it's the best approach and also, I can't see how to communicate the details to and from the child dialog.
I've tried looking at online tutorials / references but what I've found is either too simplistic or focuses on things like tkMessageBox.showinfo() which iss not what I want.
There are at least a couple ways to solve your problem. Either your dialog can directly send information to the main application, or your dialog can generate an event that tells the main application that data is really to be pulled from the dialog. If the dialog simply changes the appearance of something (for example, a font dialog) I usually generate an event. If the dialog creates or deletes data I typically have it push information back to the application.
I typically have an application object that acts as the controller for the GUI as a whole. Often this is the same class as the main window, or it can be a separate class or even defined as a mixin. This application object has methods that dialogs can call to feed data to the application.
For example:
class ChildDialog(tk.Toplevel):
def __init__(self, parent, app, ...)
self.app = app
...
self.ok_button = tk.Button(parent, ..., command=self.on_ok)
...
def on_ok(self):
# send the data to the parent
self.app.new_data(... data from this dialog ...)
class MainApplication(tk.Tk):
...
def on_show_dialog(self):
dialog = ChildDialog(self)
dialog.show()
def new_data(self, data):
... process data that was passed in from a dialog ...
When creating the dialog, you pass in a reference to the application object. The dialog then knows to call a specific method on this object to send data back to the application.
If you're not into the whole model/view/controller thing you can just as easily pass in a function rather than an object, effectively telling the dialog "call this function when you want to give me data".
In one of my projects I was trying to check within a child tk.Toplevel window (child1) of my root window (self), if a tk.Toplevel window (child2) was created by the user from within the root window, and if this window (child2) is present at the users screen at the moment.
If this wouldn't be the case, the new tk.Toplevel window should gets created by the child window (child1) of the root window, instead of the root window itself. And if it was already created by the root window and is currently present at the users screen, it should get focus() instead of getting reinitialized by "child1".
The root window was wrapped inside a class called App() and both "children" windows were created by methods inside the root class App().
I had to initialize "child2" in a quiet mode if an argument given to the method was True. I suppose that was the entangled mistake. The problem occurred on Windows 7 64 bit, if that's significant.
I tried this (example):
import tkinter as tk
from tkinter import ttk
class App(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
top = self.winfo_toplevel()
self.menuBar = tk.Menu(top)
top['menu'] = self.menuBar
self.menuBar.add_command(label='Child1', command=self.__create_child1)
self.menuBar.add_command(label='Child2', command=lambda: self.__create_child2(True))
self.TestLabel = ttk.Label(self, text='Use the buttons from the toplevel menu.')
self.TestLabel.pack()
self.__create_child2(False)
def __create_child1(self):
self.Child1Window = tk.Toplevel(master=self, width=100, height=100)
self.Child1WindowButton = ttk.Button(self.Child1Window, text='Focus Child2 window else create Child2 window', command=self.CheckForChild2)
self.Child1WindowButton.pack()
def __create_child2(self, givenarg):
self.Child2Window = tk.Toplevel(master=self, width=100, height=100)
if givenarg == False:
self.Child2Window.withdraw()
# Init some vars or widgets
self.Child2Window = None
else:
self.Child2Window.TestLabel = ttk.Label(self.Child2Window, text='This is Child 2')
self.Child2Window.TestLabel.pack()
def CheckForChild2(self):
if self.Child2Window:
if self.Child2Window.winfo_exists():
self.Child2Window.focus()
else:
self.__create_child2(True)
else:
self.__create_child2(True)
if __name__ == '__main__':
App().mainloop()
Here comes the problem:
I wasn't able to check if "child2" is already present. Got error: _tkinter.TclError: bad window path name
Solution:
The only way to get the right 'window path name' was, instead of calling the winfo_exists() method directly onto the "child2" window, calling the master of the "child1" window and adding the according attributes followed by the attributes of the master window you want to use.
Example (edit of the method CheckForChild2):
def CheckForChild2(self):
if self.Child2Window:
if self.Child1Window.master.Child2Window.winfo_exists():
self.Child1Window.master.Child2Window.focus()
else:
self.__create_child2(True)
else:
self.__create_child2(True)