def create_peer_widget(original_text_widget: tkinter.Text, the_widget_that_becomes_a_peer: tkinter.Text) -> None: """ Make sure that *the_widget_that_becomes_a_peer* always has the same content as *original_text_widget*. For details, see the ``PEER WIDGETS`` section in `text(3tk) <https://www.tcl.tk/man/tcl8.7/TkCmd/text.htm>`_. This is useful for e.g. :source:`porcupine/plugins/minimap.py`. .. warning:: This does **not** create a red text widget:: the_widget_that_becomes_a_peer = tkinter.Text(master, background='red') create_peer_widget(original_text_widget, the_widget_that_becomes_a_peer) This works better:: the_widget_that_becomes_a_peer = tkinter.Text(master) create_peer_widget(original_text_widget, the_widget_that_becomes_a_peer) the_widget_that_becomes_a_peer.config(background='red') All widget options of *the_widget_that_becomes_a_peer* are lost when this function is called. I tried to make this function preserve the widget options but that caused weird problems. Notes about using :func:`create_peer_widget` and :func:`track_changes` together: * Call :func:`track_changes` with *original_text_widget*, not with its peers. If you get this wrong, you will get a :class:`RuntimeError`. * Bind to the ``<<ContentChanged>>`` with the original widget, not with the peers. If you get this wrong, your ``<<ContentChanged>>`` callback won't run. * First call :func:`track_changes` and then :func:`create_peer_widget`. If you get this wrong, you will get a :class:`RuntimeError`. """ # Peer widgets are weird in tkinter. Text.peer_create takes in a # widget Tcl name, and then creates a peer widget with that name. # But if you want to create a tkinter widget, then you need to let # the tkinter widget to create a Tcl widget with a name chosen by # tkinter. That has happened already when this function runs. # # Can't do .destroy() because that screws up winfo_children(). Each tkinter # widget knows its child widgets, and .destroy() would make tkinter no # longer know it. Tkinter's winfo_children() ignores unknown widgets. the_widget_that_becomes_a_peer.tk.call("destroy", the_widget_that_becomes_a_peer) original_text_widget.peer_create(the_widget_that_becomes_a_peer) change_tracker = _change_trackers.get(original_text_widget) if change_tracker is not None: change_tracker.setup(the_widget_that_becomes_a_peer)
def create_peer_widget( original_text_widget: tkinter.Text, the_widget_that_becomes_a_peer: tkinter.Text, ) -> None: """ Make sure that *the_widget_that_becomes_a_peer* always has the same content as *original_text_widget*. For details, see the ``PEER WIDGETS`` section in `text(3tk) <https://www.tcl.tk/man/tcl8.7/TkCmd/text.htm>`_. This is useful for e.g. :source:`porcupine/plugins/overview.py`. .. warning:: This does **not** create a red text widget:: the_widget_that_becomes_a_peer = tkinter.Text(master, background='red') create_peer_widget(original_text_widget, the_widget_that_becomes_a_peer) This works better:: the_widget_that_becomes_a_peer = tkinter.Text(master) create_peer_widget(original_text_widget, the_widget_that_becomes_a_peer) the_widget_that_becomes_a_peer.config(background='red') All widget options of *the_widget_that_becomes_a_peer* are lost when this function is called. I tried to make this function preserve the widget options but that caused weird problems. Notes about using :func:`create_peer_widget` and :func:`track_changes` together: * Bind to the ``<<ContentChanged>>`` event of *original_text_widget*, not *the_widget_that_becomes_a_peer*. **Make sure to get this right** to avoid issues with ``<<ContentChanged>>`` sometimes not triggering. If you create peers of peers, then bind to the most original widget, not any of its peers. * First call :func:`track_changes` and then :func:`create_peer_widget`. You will get a :class:`RuntimeError` if you screw this up. """ # Peer widgets are weird in tkinter. Text.peer_create takes in a # widget Tcl name, and then creates a peer widget with that name. # But if you want to create a tkinter widget, then you need to let # the tkinter widget to create a Tcl widget with a name chosen by # tkinter. That has happened above with the super() call. However, # rest of what happens in this __init__ method must do stuff to the # peer widget, rather than the widget that tkinter created. # # Can't do .destroy() because that screws up winfo_children(). Each tkinter # widget knows its child widgets, and .destroy() would make tkinter no # longer know it. Tkinter's winfo_children() also ignores anything not # known to tkinter. # # issues related to type ignore comments: # https://github.com/python/mypy/issues/6552 # https://github.com/python/typeshed/issues/4409 the_widget_that_becomes_a_peer.tk.call('destroy', the_widget_that_becomes_a_peer) original_text_widget.peer_create(the_widget_that_becomes_a_peer) if original_text_widget in _change_tracked_widgets: track_changes(the_widget_that_becomes_a_peer) utils.forward_event('<<ContentChanged>>', the_widget_that_becomes_a_peer, original_text_widget)