-1

I want to create a log window where I show records of error or success messages. Please tell me any solution to insert text in text_box from any widget in current application.

Is any solution like we use textvariable

Purpose: Suppose we have two tabs, in one we are downloading something and some error comes in it, then this error is inserted in the text box of the other tab.

I am updating my question to get better answer.

File Structure:

enter image description here

downloader.py

import tkinter as tk


class DownloadWindow(tk.Frame):
    def __init__(self, parent):
        super().__init__(parent)
        ################# self configure ##########################
        self.columnconfigure(0, weight=1)

        ############### entry ################################
        self.entry = tk.Entry(self)
        self.entry.grid(row=0, column=0, sticky='nsew')
        self.entry.insert(0, 'I am error send me to Logs...')

        ################ Button #################################
        self.button = tk.Button(self, text='Send to Log')
        self.button.grid(row=1, column=0, sticky='nsew')

insert.py

"""
Help me to write a function in this module for button in downloader
"""

logs.py

import tkinter as tk


class LogWindow(tk.Frame):
    def __init__(self, parent):
        super().__init__(parent)
        ################# self configure ##########################
        self.rowconfigure(0, weight=1)
        self.columnconfigure(0, weight=1)
        self.text_box = tk.Text(self, wrap=None, bg='black', font='roboto 14 bold')
        self.text_box.grid(row=0, column=0, sticky='nsew')

        self.scroller = tk.Scrollbar(self, command=self.text_box.yview, orient='vertical')
        self.text_box.configure(yscrollcommand=self.scroller.set)
        self.scroller.grid(row=0, column=1, sticky='nse')

        self.text_box.tag_configure('welcome', foreground='white', background='black')
        self.text_box.tag_configure('error', foreground='red')
        self.text_box.tag_configure('success', foreground='green')

        self.text_box.insert('end', '>>> Welcome to Log Window', 'welcome')
        self.text_box.insert('end', '\n>>> Completed', 'success')
        self.text_box.insert('end', '\n>>> Something Wrong in Data Download', 'error')


luncher.py

import tkinter as tk
from tkinter import ttk
from Test.logs import LogWindow
from Test.downloader import DownloadWindow
root = tk.Tk()

base_tab = ttk.Notebook(root)
base_tab.grid(row=0, column=0, sticky='nsew')


base_tab.add(DownloadWindow(base_tab), text='Download')
base_tab.add(LogWindow(base_tab), text='Logs')

root.mainloop()

Screenshot:

enter image description here

enter image description here

Final Update and Goal Achived

Added In downloader.py

        self.button.config(command=self.create_log)

    def create_log(self):
        write_log(self.entry.get())

Added In insert.py

def write_log(text):
    with open('logs_data.txt', 'a') as log:
        log.write(f'\n{text}')

Added In logs.py

        self.show_log()

    def show_log(self):
        global file_name, cached_stamp
        stamp = os.path.getmtime(file_name)
        if stamp != cached_stamp:
            with open(file_name, 'r') as log:
                data = log.readlines()
                self.text_box.insert('end', f'\n{data[-1]}', 'success')
        cached_stamp = stamp
        self.after(1000, self.show_log)

Conclusion

I am appending each log in .txt file and reading them in every sec. from LogWindow and detecting change. If change occur then inserting in Text widget.

Manish Pushpam
  • 146
  • 2
  • 16
  • 2
    You can nsert text into it by calling `self.text_box.insert()` — the same way you do it in the `Windows.__init__()` method, – martineau Oct 10 '20 at 11:00
  • @martineau sir I can't create object in insert module because I am using insert module multiple time. Is there any function based solution. – Manish Pushpam Oct 10 '20 at 11:14
  • Despite your update, you question remains unclear. I think I know how to create a `Text`-like widget that supports a `textvariable=` option. However it's (still) unclear how having one fits into what you want in the `insert` module. None of your code contains any clues as to the interface you desire it to have (other than maybe it contains a function of some sort). You seem to have an idea, but we can't read your mind… – martineau Oct 10 '20 at 12:41
  • @martineau: the "function-based solution" is to call the `insert` method on the text widget. `insert` is a function. This is literally the only way to insert text into a widget. – Bryan Oakley Oct 10 '20 at 12:46
  • @Bryan: What object? Where is it created? How do other modules access it? – martineau Oct 10 '20 at 12:48
  • @BryanOakley sir according to screenshot presentation is there any other way to achieve this. Instead of Text widget. – Manish Pushpam Oct 10 '20 at 12:53
  • @martineau sir I just want that error text in log tab. – Manish Pushpam Oct 10 '20 at 12:54
  • Manish: I know, I just don't understand *how* you want that to happen. Just saying it's done in some code in certain module does not describe an interface nor sample usage of it. – martineau Oct 10 '20 at 12:57
  • The title of your question specifically asks how to insert text into a text widget. The only answer to that can be found in the documentation, and that is to call the `insert` method. That's it. That's all there is. – Bryan Oakley Oct 10 '20 at 13:03
  • @martineau Sir, forget my module structure and see both screenshots, do you see any idea to achieve this? – Manish Pushpam Oct 10 '20 at 13:04
  • Manish: See @BryanOakley's [answer](https://stackoverflow.com/a/21565476/355230) to another question that has the defintion of a `Text`-like widget that supports a `textvariable` – martineau Oct 10 '20 at 13:04
  • @BryanOakley Sir After a lot of thinking, I have reached to a solution, can you see this and tell me am I right? – Manish Pushpam Oct 11 '20 at 05:50
  • @martineau Sir After a lot of thinking, I have reached to a solution, can you see this and tell me am I right? – Manish Pushpam Oct 11 '20 at 05:50
  • Manish: From what I can tell it looks like it would work. I thought you wanted something more dynamic than that which would cause the various `Text` widget associated it to update themselves automatically whenever `StringVar` was changed. – martineau Oct 11 '20 at 06:35

1 Answers1

0

Your question is very unclear. I don't know if it's a language barrier or just a problem with terminology. I'm guessing that you're not actually asking how to insert text into a widget since that is clearly documented, but rather how to create the widget in one class and access it from another.

If that is the case, then my recommendation is to do two things: create a method in LogWindow to insert text into the text widget, and then call that method from anywhere else in the app.

Create a logging method in LogWindow

The firs step is to create a function in LogWindow that other objects can use to add data to the log. The following example creates an info method which accepts a string and adds it to the text widget:

class LogWindow(tk.Frame):
    def __init__(self, parent):
        ...
        self.text_box = tk.Text(...)
        ...
        
    def info(self, message):
        self.text_box.insert("end", message)
        if not message.endswith("\n"):
            self.text_box.insert("end", "\n")

Modify DownloadWindow to accept instance of LogWindow

Next, you need to make sure that other code can call this method. You can either do that by setting a global variable, by creating a global controller that all tabs can access, or by passing the reference to the other tabs.

Arguably the simplest method is to just pass the instance to other classes. You can do that by first modifying DownloadWindow to accept the log window as a parameter:

class DownloadWindow(tk.Frame):
    def __init__(self, parent, logwindow):
        super().__init__(parent)
        self.logger = logwindow

Once you do that, you can use self.logger.info("...") anywhere in the class to send a message to the log window.

Passing the instance of LogWindow to DownloadWindow

The final step is to pass the instance of LogWindow to DownloadWindow. This requires creating the instance of LogWindow first, saving a reference, and passing that reference to DownloadWindow

log_window = LogWindow(base_tab)
download_window =  DownloadWindow(base_tab, log_window)

base_tab.add(download_window, text='Download')
base_tab.add(log_window, text='Logs')
Bryan Oakley
  • 370,779
  • 53
  • 539
  • 685