Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Widget IDs are not cleared when a window closes #2514

Closed
ethindp opened this issue Apr 19, 2024 · 5 comments · Fixed by #2517
Closed

Widget IDs are not cleared when a window closes #2514

ethindp opened this issue Apr 19, 2024 · 5 comments · Fixed by #2517
Labels
bug A crash or error in behavior.

Comments

@ethindp
Copy link

ethindp commented Apr 19, 2024

Describe the bug

When a window is created upon the click of a button or other widget in a main window, IDs of widgets within that sub-window are not cleared, causing window creation and displaying to fail when the window is closed and re-opened.

Steps to reproduce

  1. Create any main window with some widget that instantiates and shows another window when the widget is pressed, clicked, etc.
  2. The sub-window should use widget IDs, such as paths (I use this format for determining which widget to update when a network event is received in my application).
  3. Close the window and try to re-open it. You will get an error along the lines of KeyError: "There is already a widget with the id '/devices/0/inputs/0/sends/0/Gain/value'"

Expected behavior

Widget IDs should be cleared when the window is either closed, deleted, or otherwise ceases to exist.

Screenshots

No response

Environment

  • Operating System: Windows 10 22H2 (AMD64) build 19045.4291
  • Python version: 3.12.2
  • Software versions:
    • Briefcase: 0.3.17
    • Toga: 0.4.2+

Logs

[19:49:53] Error in handler: "There is already a widget with the id '/devices/0/inputs/0/sends/0/Gain/value'"                                                      subprocess.py:681
           Traceback (most recent call last):                                                                                                                      subprocess.py:681
             File "C:\Users\ethin\source\venvs\uaccess\Lib\site-packages\toga\handlers.py", line 80, in _handler                                                   subprocess.py:681
               result = handler(interface, *args, **kwargs)                                                                                                        subprocess.py:681
                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^                                                                                                        subprocess.py:681
             File "C:\Users\ethin\source\uaccess\src\uaccess\app.py", line 216, in open_sends                                                                      subprocess.py:681
               self.sends_dialogs[widget.id].build()                                                                                                               subprocess.py:681
             File "C:\Users\ethin\source\uaccess\src\uaccess\dialogs\sends_dialog.py", line 27, in build                                                           subprocess.py:681
               self.sends_content.add(edit)                                                                                                                        subprocess.py:681
             File "C:\Users\ethin\source\venvs\uaccess\Lib\site-packages\toga\widgets\base.py", line 100, in add                                                   subprocess.py:681
               child.window = self.window                                                                                                                          subprocess.py:681
               ^^^^^^^^^^^^                                                                                                                                        subprocess.py:681
             File "C:\Users\ethin\source\venvs\uaccess\Lib\site-packages\toga\widgets\base.py", line 227, in window                                                subprocess.py:681
               window.app.widgets._add(self)                                                                                                                       subprocess.py:681
             File "C:\Users\ethin\source\venvs\uaccess\Lib\site-packages\toga\app.py", line 192, in _add                                                           subprocess.py:681
               raise KeyError(f"There is already a widget with the id {widget.id!r}")                                                                              subprocess.py:681
           KeyError: "There is already a widget with the id '/devices/0/inputs/0/sends/0/Gain/value'"                                                              subprocess.py:681

Additional context

No response

@ethindp ethindp added the bug A crash or error in behavior. label Apr 19, 2024
@freakboy3742
Copy link
Member

Thanks for the report. If you're able to provide actual code for a minimal reproduction example, rather than a "word description" of the problem, that would be a lot more helpful for debugging purposes, as it guarantees we're looking at the same problem you are.

@ethindp
Copy link
Author

ethindp commented Apr 19, 2024

The repro is something along the lines:

import toga

class SendsDialog(toga.Window):
	def __init__(self, device_id, input_id):
		super().__init__(title="Edit Sends", size=(400, 200))
		self.sends_content = toga.Box()
		self.input = input_id
		self.device = device_id
		self.content = self.sends_content

	def build(self):
		path = f"/devices/0/inputs/0/sends/0/Gain/value"
		sendname = "AUX 1"
		val = -144.0
		default = -144.0
		min = -144.0
		max = 12.0
		label = toga.Label(f"{sendname} Gain")
		edit = toga.NumberInput(id=path, step=1.0, min=min, max = max, value = val if val is not None else default, on_change=self.on_prop_float_change)
		self.sends_content.add(label)
		self.sends_content.add(edit)
		self.sends_content.add(toga.Button("&Close", on_press=self.close_window))

	async def on_prop_float_change(self, widget, *args, **kwargs):
		pass # Do nothing

	def close_window(self, widget, *args, **kwargs):
		self.close()

class Repro(toga.App):
	def startup(self):
		self.on_exit = self.handle_exit
		self.main_window = toga.MainWindow(title=f"{self.formal_name} [Loading]")
		self.main_container = toga.Box(
			style=Pack(direction=COLUMN, padding=10),
		)
		self.sends_btn = toga.Button("&Sends", on_press=self.open_sends)
		self.main_container.content.append(self.sends_btn)
		self.main_window.content = self.main_container
		self.main_window.show()

	async def close_app(self, widget, **kwargs):
		self.exit()

	def open_sends(self, widget, *args, **kwargs):
		dialog = SendsDialog(0, 0)
		dialog.build()
		dialog.show()

def main():
	return Repro()

@proneon267
Copy link
Contributor

A simplified reproducible example of the above would be:

import toga


class HelloWorld(toga.App):
    def startup(self):
        self.main_window = toga.MainWindow(title=f"{self.formal_name}")
        self.main_window.content = toga.Box(
            children=[toga.Button("Open Second Window", on_press=self.do_open_window)]
        )
        self.main_window.show()

    def do_open_window(self, widget, *args, **kwargs):
        window = toga.Window()
        window.content = toga.Box(
            children=[toga.Label(text="Sample Label", id="sample_label")]
        )
        window.show()


def main():
    return HelloWorld()

The title should be changed to clarify that the bug is with widget IDs not with window IDs.

@ethindp ethindp changed the title Window IDs are not cleared when a window closes Widget IDs are not cleared when a window closes Apr 20, 2024
@ethindp
Copy link
Author

ethindp commented Apr 20, 2024

@proneon267 Thanks for that simplification, I wasn't sure if I'd done it right. I've updated both the issue title and the original comment to specifically indicate that this occurred with widget IDs -- somehow I didn't notice that or my brain filtered it out :P

@proneon267
Copy link
Contributor

No worries :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug A crash or error in behavior.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants