Typing effect in GraphWin - python

I'm trying to create a text typing effect in a window, however it comes up as
"TypeError: 'Text' object is not iterable". Here's my current code:
from graphics import *
import sys
from time import sleep
window = GraphWin('Test', 1000, 700)
text = Text(Point(500, 150), "This is just a test :P")
words = ("This is just a test :P")
for char in text:
sleep(0.1)
sys.stdout.write(char)
sys.stdout.flush()
word.draw(window)
Source for typing effect
The text comes up in the shell if I use the 'words' variable, however becomes a TypeError if I try using the text variable. Is there a way of making it iterable?

First, you are getting mixed up and confusing your variables text and words; second, your Text object is not iterable, but you can create several ones to be displayed in succession while iterating over `words'
from graphics import *
import sys
from time import sleep
window = GraphWin('Test', 1000, 700)
text = Text(Point(500, 150), "This is just a test :P")
words = "This is just a test :P"
# this prints to console
for char in words:
sleep(0.1)
sys.stdout.write(char)
sys.stdout.flush()
# that displays on canvas
for idx, t in enumerate(words):
text = Text(Point(300+idx*20, 150), t)
text.draw(window)
sleep(0.1)
In python 3, you can replace the calls to sys.stdout with standard print calls:
# this prints to console
for char in words:
sleep(0.1)
print(char, end='', flush=True)

Related

PIL not writing text a second time onto image

I'm trying to make a somewhat ambitious hangman game for a discord bot, and for that I need PIL to write in text. After writing some text to an image, and then trying to write text again to that same image, instead of sending the image with the second text added, it only sends the image with the first text. The weird thing is, is that the function goes through, it saves it as a new file with a different name, but no text (the second set, that is). What gives? What am I doing wrong here?
import random, discord
from requests import get as reGet
from io import BytesIO
from PIL import Image, ImageDraw, ImageFont
# Just a random image I found off google, not actually using it
inp_shell = reGet("https://upload.wikimedia.org/wikipedia/commons/thumb/a/a0/Circle_-_black_simple.svg/1200px-Circle_-_black_simple.svg.png")
# Yes, I know, probably not the best place to put the font, I'll change it later
fnt = ImageFont.truetype("modules/Roboto-Regular.ttf", size= 40)
# Opens a list of words that it can get from; The file here is just a stub
with open('words_alpha.txt') as words_file:
word_list = words_file.read().splitlines()
class img():
def __init__(self):
self.open_shell = Image.open(BytesIO(inp_shell.content))
# Text in the top left
async def tLeft(self, txt, inp_img):
image = ImageDraw.Draw(inp_img)
image.text((10,10), txt, font=fnt, fill=(0, 0, 0))
self.open_shell.save("tLeft.png")
async def main_text(self, txt, inp_img):
image = ImageDraw.Draw(inp_img)
# Used to position the text in the center but currently is not being used
x, y = inp_img.size
pos = x/2
# I've tried changing the fill and position, and still nothing.
# This is probably the source of the problem
image.text((20,20), txt, font=fnt, fill=(255, 255, 255))
print(txt)
self.open_shell.save("mainText.png")
# Creates a dictionary with the length of the words assigned as they keys,
# I think anyways, I didn't write this
by_length = {}
for word in word_list:
by_length.setdefault(len(word), []).append(word)
# Retrieves a random word with a certain length
async def word_finder(wordlength):
global word
word = random.choice(by_length[wordlength])
print(word)
# Main function
async def hanggMan(message): #double g in hang is intentional
content = message.clean_content[11:]
print(content) # Just used to make sure it's going through
# For now I'm using a word length of 5
if content.lower() == "5":
z = img() # Calls an instance of the img class
# Puts the image in an embed; ignore t his
embed = discord.Embed(title="testtest testtesttesttest")
embed.type = "rich"
embed.colour = discord.Color.gold()
await word_finder(5) # Tells the word_finder function to find a random word with a length of 5
await z.tLeft(txt="tLeft", inp_img= z.open_shell) # Calls the tLeft function and tells it to write "tLeft"
# Calls the main_text function and tells it to write the word on top of
# "tLeft.png". There is a print statement in the function and it actually
# does print the word, so this is not likely to be the source of the problem
await z.main_text(txt=word, inp_img=Image.open("tLeft.png"))
embed.set_image(url="attachment://mainText.png")
# The interesting thing about this is that it actually does save it as "mainText.png"
# and sends the file properly, but the word is nowhere to be found
await message.channel.send(embed=embed, file=discord.File("mainText.png"))
I can't run it but when I start removing not imprtant code then I saw you use image in class img() in wrong way.
You always save image which you have in self.open_shell
In first function you send the same image as argument
z.tLeft(txt="tLeft", inp_img=z.open_shell)
so add text to z.open_shell and you save z.open_shell
But in function you send different image as argument
z.main_text(txt=word, inp_img=Image.open("tLeft.png"))
so you add text to new image but you save again z.open_shell which has older version.
You need
self.open_shell = inp_img
Like this
def main_text(self, txt, inp_img):
self.open_shell = inp_img
image = ImageDraw.Draw(inp_img)
image.text((20,20), txt, font=fnt, fill=(255, 255, 255))
self.open_shell.save("mainText.png")

print out to 7" screen and then clear monitor using textwrapper + console login

I am working on a project/installation that will be run on a 7" monitor. At the moment the project selects a sentence from a txt file and then prints it out to using a typewriter effect. Using textwrapper the sentence will split over as many lines needed.
import tweepy
from time import sleep
from credentials import *
import nltk.data
import random
import sys
import textwrap
# Access and authorize our Twitter credentials from credentials.py
auth = tweepy.OAuthHandler(consumer_key, consumer_secret)
auth.set_access_token(access_token, access_token_secret)
api = tweepy.API(auth)
# Open text file newMaster.txt for reading
my_file = open('newMaster.txt', 'r')
text = my_file.read()
# close the file
my_file.close()
#Loop
while True:
#ntlk tokenizer
tokenizer = nltk.data.load('tokenizers/punkt/english.pickle')
#my code takes text file
forTweet = text
#breaks into sentences
tok = tokenizer.tokenize(forTweet)
#selects random sentence
newTok = random.choice(tok)
#makes sure sentence is less than 280 characters
newTok = random.choice([x for x in tok if len(x)<280])
#text wrap to make sure words do not split on
str2 = textwrap.fill(newTok, 128)
#Gets length of newTOk
lenghtnewTok = len(newTok)
#Keeps text on screen for 5 seoncds
sleep(5)
# initialise clearing screen
stdscr = curses.initscr()
# Clear the screen
stdscr.clear()
#keep screen clear for 2 seconds
sleep(2)
#This is typewrite effect
words = str2.replace('\n', '\r\n')
for char in words:
sleep(0.1)
sys.stdout.write(char)
sys.stdout.flush()
However, what I would now like to acheive is that instead of printing 1 sentence, the script will:
1.select one sentence, print using typewriter effect.
Wait two seconds, skip a line and then print another sentence.
Keep doing this until it reaches bottom of screen and then clear all sentences and start again from the top.
Any suggestions would be great.

Tkinter: How to make characters appear on text widget with a time delay?

def write_text(widget, message, enter_number, slow_type=True):
widget.config(state="normal")
if slow_type:
if len(message) > 0:
widget.insert("insert", message[0])
if len(message) > 1:
widget.after(100, UI.write_text, widget, message[1:], 0)
else:
widget.insert("insert", message)
for i in range(enter_number):
widget.insert("insert", "\n")
widget.config(state="disabled")
widget.see("end")
This is my code to write each characters show up in time delay
But I have a problem:
If I call this method like this (I have a widget named text1).
write_text(text1, ">>>Invalid Input", 1)
write_text(text1, ">>>Try Again...", 2)
Messages blend together something like this >>>>>>ITnrvya lAigda iInn.p.u.t.
I want it to type messages when typing the previous message is over.
What can I do?
P.S. Sorry for my bad English...
Here's something runnable that does what I think you want. The "blended" output you're getting was because the second call you have to write_text() occurs before all the (delayed) processing of the first one has completed, so the text widget effectively gets updates by two separate callback processes.
The code below avoids this issue by putting the characters of the string (and what line they go on) in a Queue which allow them to be retrieved in the same order that they were added.
DELAY = 100 # ms between widget updates
def update_widget(widget):
try:
line_number, text = widget._text_queue.get_nowait()
except queue.Empty:
return # Nothing further to do.
widget.insert('%s.end' % line_number, text)
if widget._text_queue.qsize(): # Anything more to process?
widget.after(DELAY, update_widget, widget)
def write_text(widget, message, line_number, slow_type=True):
if not slow_type:
widget.insert('%s.0' % line_number, message)
else:
for ch in message: # Add each character of message to queue.
widget._text_queue.put((line_number, ch))
update_widget(widget) # Start (or continue) update processing.
def add_text(widget):
widget.delete('1.0', tk.END) # Delete widget's current contents.
# Note: Tkinter always adds a newline at the very end of text widgets, so
# we need one less newline. This makes it possible to insert text onto
# any possible line of the widget -- which could fail if it was empty.
widget.insert('1.0', (widget['height']-1) * '\n') # Init with blank lines.
write_text(widget, ">>>Invalid Input", 1)
write_text(widget, ">>>Try Again...", 2)
if __name__ == '__main__':
root = tk.Tk()
text1 = tk.Text(root, width=40, height=3, bg='skyblue')
text1._text_queue = queue.Queue() # Add a Queue to it for delayed updates.
text1.grid()
button = tk.Button(root, text='Run Test', command=lambda w=text1: add_text(w))
button.grid()
root.mainloop()

(PyQt) How can I reset the CharFormat of an entire QTextEdit?

I'm using mergeCharFormat on several words within my QTextEdit, in an effort to highlight them. Something like this:
import sys
from PyQt4 import QtGui, uic
from PyQt4.QtCore import *
def drawGUI():
app = QtGui.QApplication(sys.argv)
w = QtGui.QWidget()
w.setGeometry(200, 200, 200, 50)
editBox = QtGui.QTextEdit(w)
text = 'Hello stack overflow, this is a test and tish is a misspelled word'
editBox.setText(text)
""" Now there'd be a function that finds misspelled words """
# Highlight misspelled words
misspelledWord = 'tish'
cursor = editBox.textCursor()
format_ = QtGui.QTextCharFormat()
format_.setBackground(QtGui.QBrush(QtGui.QColor("pink")))
pattern = "\\b" + misspelledWord + "\\b"
regex = QRegExp(pattern)
index = regex.indexIn(editBox.toPlainText(), 0)
cursor.setPosition(index)
cursor.movePosition(QtGui.QTextCursor.EndOfWord, 1)
cursor.mergeCharFormat(format_)
w.showFullScreen()
sys.exit(app.exec_())
if __name__ == '__main__':
drawGUI()
So, this highlighting feature works exactly as intended. However, I can't find a good way to clear the highlights from the textarea. What is a good method of doing such a thing- essentially just setting the char format of the entire QTextEdit back to its defaults?
What I've tried so far is getting the cursor again, and setting its format to a new format with a clear background, then putting the cursor over the entire selection and using QTextCursor.setCharFormat(), but this appears to do nothing.
Applying a new QTextCharFormat to the whole document works for me:
def drawGUI():
...
cursor.mergeCharFormat(format_)
def clear():
cursor = editBox.textCursor()
cursor.select(QtGui.QTextCursor.Document)
cursor.setCharFormat(QtGui.QTextCharFormat())
cursor.clearSelection()
editBox.setTextCursor(cursor)
button = QtGui.QPushButton('Clear')
button.clicked.connect(clear)
layout = QtGui.QVBoxLayout(w)
layout.addWidget(editBox)
layout.addWidget(button)

Tkinter clearing formatting from syntax highlighting

I have syntax highlighting implemented in Python using Tkinter. For example, I can make it automatically highlight "derp". The problem is that when I modify the string to, say, "dERP"or something similar, it will still highlight the "d" (aka the only remaining original character). How do I clear formatting on this? I've considered creating a tag that will set the background to white for the entire document, but then this creates problems with highlighting.
code:
from Tkinter import *
import sys, os
class easyTex(Text):
def __init__(self,base,**args):
Text.__init__(self,base,**args)
self.tag_configure("default", background="white")
self.tag_configure("search", background="blue")
def highlightPattern(self, pattern, tag):
start = "1.0"
countVar = StringVar()
while True:
pos = self.search(pattern, start, stopindex="end", count=countVar, regexp=True)
if not pos: break
self.tag_add(tag, pos, "%s+%sc" % (pos, countVar.get()))
start = "%s+%dc" % (pos, int(countVar.get()) + 1)
def highlightSyntax(self):
self.highlightPattern(".*", "default")
self.highlightPattern("a red car", "search")
base = Tk()
editor = easyTex(base)
base.bind("<Escape>", lambda e: sys.exit())
base.bind("<Key>", lambda e: editor.highlightSyntax())
editor.pack(fill=BOTH, expand=1)
base.call('wm', 'attributes', '.', '-topmost', True)
mainloop()
(this is using the regex: "a red car":)
To remove the effects of a tag, remove the tag from the range of characters. You can remove a tag with tag_remove, giving it a starting and ending range that you want the tag removed from.
For example, to remove the "search" tag from the entire document, do this:
self.tag_remove("search", "1.0", "end")

Categories

Resources