2

I have this source code:

from Tkinter import *
import tkMessageBox
import time
class Window(Tk):
    def __init__(self,parent):
        Tk.__init__(self,parent)
        self.parent = parent
        self.initialize()


    def initialize(self):
        self.geometry('450x250+0+0')
        self.configure(background="#379DDB")
        self.title('Konversi Bilangan')
        **self.label = Label(self, text='Konversi Dari',font=('times',24,'italic'),bg="#379DDB")**
        self.label.pack()
        self.tombol=Button(self, text='Biner',font=(18),borderwidth='3px',width=10,command=self.OnButtonClick1,bg="#69ABD3")
        self.tombol.pack(side=TOP)
        self.tombol2=Button(self, text='Desimal',font=(18),borderwidth='3px' ,width=10, command=self.OnButtonClick2,bg="#69ABD3")
        self.tombol2.pack(side=TOP)
        self.tombol3=Button(self, text='Oktal',font=(18),borderwidth='3px' ,width=10,command=self.OnButtonClick3,bg="#69ABD3")
        self.tombol3.pack()
        self.tombol4=Button(self, text='Hexa',font=(18),borderwidth='3px' ,width=10,command=self.OnButtonClick4,bg="#69ABD3")
        self.tombol4.pack()
        self.tombol5=Button(self,text='Quit',font=(18),borderwidth='3px' ,width=10, fg='red', command= self.quit,bg="#69ABD3")
        self.tombol5.pack()

How to make marquee from that I bold? If it is not possible how to make marquee like vb in tkinter?

Mika Sundland
  • 18,120
  • 16
  • 38
  • 50
  • 1
    Possible duplicate of [simple animation using tkinter](https://stackoverflow.com/questions/11502879/simple-animation-using-tkinter) – Aran-Fey Nov 10 '17 at 16:13
  • See the linked question for a recipe on how to animate things in tkinter. In your case you would of course update the marquee instead of drawing an image. – Aran-Fey Nov 10 '17 at 16:20
  • @stefan please avoid posting your question twice. Wait patiently for someone to respond to you on your question. – mauris Nov 15 '17 at 07:46

4 Answers4

3

The pattern for doing animation in tkinter is to use after to schedule one frame of the animation at a time. It looks something like this, where fps is defined as the number of frames you want per second, and widget is a tkinter widget:

def animate():
    <draw one frame of animation>
    widget.after(int(1000/fps), animate)

As for a marquee, one of the easiest solutions is to use a canvas, since it has a convenient move method that can be used to move text from right to left.

Here's an example:

import tkinter as tk

class Marquee(tk.Canvas):
    def __init__(self, parent, text, margin=2, borderwidth=1, relief='flat', fps=30):
        super().__init__(parent, borderwidth=borderwidth, relief=relief)

        self.fps = fps
        
        # start by drawing the text off screen, then asking the canvas
        # how much space we need. Use that to compute the initial size
        # of the canvas. 
        text = self.create_text(0, -1000, text=text, anchor="w", tags=("text",))
        (x0, y0, x1, y1) = self.bbox("text")
        width = (x1 - x0) + (2*margin) + (2*borderwidth)
        height = (y1 - y0) + (2*margin) + (2*borderwidth)
        self.configure(width=width, height=height)

        # start the animation
        self.animate()

    def animate(self):
        (x0, y0, x1, y1) = self.bbox("text")
        if x1 < 0 or y0 < 0:
            # everything is off the screen; reset the X
            # to be just past the right margin
            x0 = self.winfo_width()
            y0 = int(self.winfo_height()/2)
            self.coords("text", x0, y0)
        else:
            self.move("text", -1, 0)

        # do again in a few milliseconds
        self.after_id = self.after(int(1000/self.fps), self.animate)
        
root = tk.Tk()
marquee = Marquee(root, text="Hello, world", borderwidth=1, relief="sunken")
marquee.pack(side="top", fill="x", pady=20)

root.mainloop()
Bryan Oakley
  • 370,779
  • 53
  • 539
  • 685
  • This is a very elegant solution, but there are a couple of things I don't understand. I'd appreciate some clarification. 1. Why do we have to use tk.Canvas.__init__()? super().__init__() causes an error: AttributeError: 'Marquee' object has no attribute 'tk' 2. If I print(self) it gives .!marquee. What does that mean? I have never seen that before. 3. How the heck does this work - self.coords("text", x0, y0)? According to the documentation coords() "returns a list of coordinates for the object in ARGS". Yet we are using it to set the coordinates!! – SadSack963 Apr 23 '22 at 23:00
  • Ah! I just found the answer to question 3 on effbot. – SadSack963 Apr 23 '22 at 23:17
  • 1
    @SadSack963: whatever documentation you are reading appears to be incorrect. `Coords` is both for getting and setting the coordinates. `.!marquee` is the internal name of the widget. This was written before `super()` was common. However, when I use `super` in this code it works just fine for me. I've edited the answer to use `super()` – Bryan Oakley Apr 24 '22 at 00:18
  • Many thanks Bryan. The tcl.tk web servers were down last night, so I couldn't check the docs there. I was just looking at the docstring on the coords() function itself, which does not mention setting the coords! The PyCharm linter issues a warning "Expected type 'float', got 'str' instead". For others looking for this info, see https://www.tcl.tk/man/tcl8.7/TkCmd/canvas.html#M42 Regarding the .!marquee, from what I read the dot indicates the root window, but The exclamation mark remains a mystery. Not that it matters, I'm just intrigued. Anyway, many thanks for posting this solution. :) – SadSack963 Apr 24 '22 at 14:14
  • 1
    @SadSack963: "." represents the root window, and is also used as a separator for deeper hierarchies just like "/" both represents the root directory and is used as a separator for deeper hierarchies of files and directories. The "!" is just a character that tkinter adds to distinguish it's internally-created names from other names. There's nothing special about it. – Bryan Oakley Apr 24 '22 at 16:03
2

This is going to be hard to integrate because tkinter doesn't "play nice" with infinite loops.

The below program written with assistance from here creates a marquee, this is simply an example to prove this can be done and is a poor way of doing this.

from tkinter import *

root = Tk()

text="Lorem Ipsum"

text = (' '*20) + text + (' '*20)

marquee = Text(root, height=1, width=20)
marquee.pack()

i = 0

def command(x, i):
    marquee.insert("1.1", x)
    if i == len(text):
        i = 0
    else:
        i = i+1
    root.after(100, lambda:command(text[i:i+20], i))

button = Button(root, text="Start", command=lambda: command(text[i:i+20], i))
button.pack()

root.mainloop()

This also uses the Text widget instead of the Label widget, mostly because it's simpler to do this way.


To start it on program launch, simply adjust it to the below:

from tkinter import *

root = Tk()

text="Lorem Ipsum"

text = (' '*20) + text + (' '*20)

marquee = Text(root, height=1, width=20)
marquee.pack()

i = 0

def command(x, i):
    marquee.insert("1.1", x)
    if i == len(text):
        i = 0
    else:
        i = i+1
    root.after(100, lambda:command(text[i:i+20], i))

command(text[i:i+20], i)

root.mainloop()
Ethan Field
  • 4,646
  • 3
  • 22
  • 43
  • ohhh i get it now thank you root.after just so much easier – Stefan Adrianus Nov 10 '17 at 15:28
  • This isn't the right way to use `after`. This is no different than calling `sleep`. – Bryan Oakley Nov 10 '17 at 15:53
  • @Rawing It's probably not the most elegant thing, but I think that it's a more tkinterish (tkinteric? tkintereric? tkinteresque?) solution now? – Ethan Field Nov 10 '17 at 16:24
  • Yes, that's better. The convoluted lambda functions aside, you don't need to call `root.update()`. Also, we should clean up this wall of comments. – Aran-Fey Nov 10 '17 at 16:26
  • @Rawing This is about as much effort as I'm willing to put into a question where the OP has expended relatively little effort. Just figured it was worthwhile answering as I couldn't find another question relating directly to creating a marquee in tkinter. – Ethan Field Nov 10 '17 at 16:29
  • how to running marquee like above without the button , so when it open it just running – Stefan Adrianus Nov 15 '17 at 07:24
  • @EthanField thanks for this answer but how you move the text in `textbox` from left. `Comment` your code for it to be easy to make changes it. – O JOE Jan 06 '20 at 21:02
  • @OJOE I'm sorry, I don't understand what you mean. [You are welcome to suggest an edit to my answer](https://stackoverflow.com/posts/47224514/edit). – Ethan Field Jan 07 '20 at 10:13
  • @EthanField the are being displayed from right to left how can do it vice versa – O JOE Jan 07 '20 at 20:21
0

I have no experience in Tkinter but I hope this will help you to understand to implement this in your code. Thanks!

import sys
import time


def main():
    program = animate()
    program.data = input("Enter string : ") + " "
    program.width = int(input("Enter width : "))
    program.animate()


class animate:
    def __init__(self):
        self.data = ""
        self.width = 0

    def animate(self):
        try:
            while True:
                for x in range(0, self.width):
                    time.sleep(0.1)
                    msg = "\r{}{}".format(" " * x, self.data)
                    sys.stdout.write(msg)
                    sys.stdout.flush()

                for x in range(self.width, 0, -1):
                    time.sleep(0.1)
                    msg = "\r{}{}".format(" " * x, self.data)
                    sys.stdout.write(msg)
                    sys.stdout.flush()
        except KeyboardInterrupt:
            print("Exiting")


if __name__ == "__main__":
    main()
Ali
  • 301
  • 1
  • 8
0

Hello I do not know if you can use this code to make an imitation of the marquee, it should be noted that it is for a window of 800 x 600 if they are other measures just have to change the 805 by the measure of the width of your window.

class MarqueeAnimation:

  def __init__(self,master=None,text="",eje_x = 0,velocity = 0):
      self.root = master
      self.marqueetext = text
      self.posx = eje_x
      self.velocity = velocity
      #Marquee Label
      self.lbl = Label(self.root,text=self.marqueetext,font=(12))
      self.reqposx = self.lbl.winfo_reqwidth() * -1
      self.lbl.place(x=0,y=250)

  def StarAnimation(self):
      try:
         self.posx += 1
         self.lbl.update()
         self.lbl.place(x=self.posx,y=265)
         if self.posx == 805:
            self.posx = self.reqposx
         self.animation = self.root.after(10,self.StarAnimation)
      except:
         pass
  
   def ChangeAnimation(self,newtext=""):
      self.lbl.configure(text=newtext)
      self.lbl.update_idletasks()
      self.reqposx = self.lbl.winfo_reqwidth() * -1

   def StopAnimation(self):
      self.root.after_cancel(self.animation)
Chema
  • 1