Text edit always uppercase - python

I'm writing a screenwriting application with PySide. What I want is to turn the characters to uppercase while the user is typing.
The following piece of code gives a runtime error saying "maximum recursion depth exceeded" every time I add a character. I get what it means and why it's happening but is there a different way?
self.cursor = self.recipient.textCursor()
self.cursor.movePosition(QTextCursor.StartOfLine)
self.cursor.movePosition(QTextCursor.EndOfLine, QTextCursor.KeepAnchor)
self.curtext = self.cursor.selectedText()
if len(self.curtext) > len(self.prevText):
self.cursor.insertText(self.curtext.upper())
self.cursor.clearSelection()
self.prevText = self.curtext
The code above runs whenever the text in the text edit widget is changed. The if statment prevents the code from running when the user hasn't insert text.

You get a recursion error probably because when fixing the input to uppercase you are changing your content and again triggering the very same fixing routine. Also you constantly change the whole line while only a part has changed and needs to be fixed.
Fortunately Qt can do this itself using a QTextCharFormat. Here is the example that automatically keeps all text in a QLineEdit upper case. And you can do much more with it like underlining or making text bold...
Example:
from PySide import QtGui
app = QtGui.QApplication([])
widget = QtGui.QTextEdit()
fmt = QtGui.QTextCharFormat()
fmt.setFontCapitalization(QtGui.QFont.AllUppercase)
widget.setCurrentCharFormat(fmt)
widget.show()
app.exec_()

Related

How to specify input language for Entry or any other input field?

In short, i try to type letters (in input components like "Entry", "Text") that are allowed by Windows language-keyboard (i'm using "Latvan(QWERTY)" keyboard) and i can't write long letters like 'ā', 'č', 'ģ' and others.
For example, when i try to write 'ā', the result is 'â'.
The interesting part - when i focus on specific GUI input fiend and change Windows keyboard-language (with "Alt+Shift" shortcut or manually) twice (for example, from "Latvan(QWERTY)" to "Russian" and back to "Latvan(QWERTY)") - then i can write all letters i needed.
What i want is to set all input fields keyboard-language so i could write all letters i want without doing things mentioned above every time i launch my GUI program.
If you need more info or there is already place where this question is answered, please leave a comment and i will act accordingly.
Edit 1:
I am using PyCharm to write my Python Tkinter code. I tried to assign necessary keyboard to my program's generated GUI form according to this guide but it didn't work (i guess that because i used it on temporary created GUI forms).
I was able to solve my problem by using pynput.
Here is simplified version of my final code:
from tkinter import *
from pynput.keyboard import Key, Controller
def change_keyboard_lang(event):
keyboard = Controller()
for i in range(2):
keyboard.press(Key.alt)
keyboard.press(Key.shift_l)
keyboard.release(Key.shift_l)
keyboard.release(Key.alt)
root = Tk()
word_input = Entry(root)
word_input.focus_set()
word_input.bind("<FocusIn>", change_keyboard_lang)
word_input.pack()
root.mainloop()
In short, if cursor is focused on Entry field "word_input", system calls function "change_keyboard_lang" that changes input language from original to other and back to original - and now i can write necessary letters.
It's not the best solution since i need to bind event to every input field in my GUI form but it gets the job done. If you have a better solution please post it here.

Creating a console in Kivy

I'm trying to write a very basic Kivy program that will use 3 different layouts to split the screen into :
a header (at the top of the screen)
a text zone (in the middle of the screen)
a console (at the bottom of the screen)
So far I was thinking to use a main gridLayout, in which I use 3 different floatLayout.
Here's what the code looks like:
class Logo(App):
def build(self):
layout = GridLayout(rows=3)
layoutTop = FloatLayout(size=(100,300))
layoutMid = FloatLayout(size=(100,300))
layoutDown = FloatLayout(size=(100,300))
logo = Image(source='imagine.png',size_hint=(.25,.25),pos=(30,380))
blank = Label(text='', font_size = '25sp',pos=(-200,100))
titre = Label(text='#LeCubeMedia',font_size='40sp',pos=(0,280))
ip = Label(text='192.168.42.1',font_size='25sp',pos=(250,280))
layoutTop.add_widget(titre)
layoutTop.add_widget(logo)
layoutTop.add_widget(ip)
layoutMid.add_widget(blank)
layout.add_widget(layoutTop)
layout.add_widget(layoutMid)
return layout
if __name__ == '__main__':
Logo().run()
Actually my problem is regarding the creation of the console. I have read a lot of the Kivy docs, but I am still looking for a good way to do this type of widget.
How do you think it would be if I send something with a Python print into my Kivy app, and then refresh as soon as I need to send something else (to erase the previous print). This way it would be a console-like. But, so far I have not much ideas..
Any ideas ?
I have seen 2 types of consoles in Kivy. The first is a multiline textinput in a scrollview where you append the new text to the old in the textinput. The second is a BoxLayout or GridLayout in a Scrollview where each console output is a separate label in the layout.
This was a attempt trying stuff out with kivy, the code is old and you might need to adjust it a bit to make it run with latest kivy. Kivy-designer also includes this. This is using the simple way of using two textinputs, 1 for history and the other for input.
A better way to do a proper console would be to use pyte and draw characters directly onto the canvas of a widget. This way one would get VT emulation for free.

How do I get the Mac "command" symbol in a Tkinter menu

I've written a Python program for a friend's business, and am using Tkinter for the interface. Up until now, all features have been added in the main program window, but I'm now adding a print feature, have created a simple "File" menu, and want to add a "Print" entry to that menu, including displaying the relevant keyboard shortcut.
On my Mac, I want the shortcut to be Command-P. I found the Mac "command" symbol's Unicode value, and have tried various ways to create an accelerator string that simply concatenates that symbol and the letter "P", but nothing works. I get either the symbol or the letter to display in the menu next to "Print", but never both.
Here is the full line of code that adds the menu item, with the latest attempt at building the string (I believe I found this unicode.join option elsewhere in Stack Overflow):
sub_menu.add_command(label="Print", command=self.print_, accelerator=unicode.join(u"\u2318", u"P"))
// Only the "P" displays
Here are some of the other options that I've tried (lines truncated for clarity). With each of these options, only the "command" symbol appears:
accelerator=u"\u2318\u0050"
accelerator=u"\u2318" + "P"
accelerator=u"\u2318" + u"P"
accelerator=u"\u2318P"
accelerator=u"".join([u"\u2318", u"P"])
Up until now I haven't had a need to learn much about Unicode strings, so perhaps there's something I'm doing wrong in that regard. However, all of the attempts that I've made have come as a result of various searches, both here and elsewhere, and so far nothing has worked. Any insight into how to make this work would be most welcome!
Python 2.7.3, Mac OS X 10.8.3
After further searching online, I finally found a page that has the solution. I was surprised (and a touch annoyed) that this solution was different than the one outlined in the PDF documentation for Tkinter 8.4 that I've been referencing thus far (the one published by New Mexico Tech). I found links to Tkinter 8.5 documentation, but they also list the incorrect process.
Anyway, it's a lot simpler than I thought, and is similar to the syntax used for key binding, but slightly different. Instead of directly including the command symbol in the accelerator string, Tkinter takes the literal word "Command" (or the abbreviated "Cmd"), and internally converts it to the displayable character "⌘" in the menu. So my resulting line is:
sub_menu.add_command(label="Print", command=self.print_, accelerator="Command-P")
...and what I get in my full menu item is:
Print ⌘P
As the page linked above shows, similar shortcut words exist for other modifier keys, and on Mac OS X, these are all automatically translated into their graphical equivalents.
It was actually really easy, all I did was use string formatting to concatenate text="%s%s" % (u"\u2318","P")
Here is a sample Tkinter App, the display is small but it shows what you need.
import Tkinter as tk
class SampleApp(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
self.label = tk.Label(text="%s%s" % (u"\u2318","P"))
self.label.pack(padx=10, pady=10)
app = SampleApp()
app.mainloop()
Output:
⌘P

Python-Tkinter Text Insert not affecting box

First time poster, found the site very helpful before registering though.
I am having issues using Tkinter on Python 2.7 (Windows7):
The code (I have truncated it because the whole thing is massive) looks something like this:
-------------------------------------------------------
CODE:
#set up stuff, importing variables, etc, then we have:
class App:
global RXSerial
RXSerial=''
#The following lines define the topFrame, lays out the widgets.
def __init__(self, master):
topFrame = Frame(master)
topFrame.pack()
middleFrame = Frame(master)
middleFrame.pack()
#--------------defining state variables------------
self.inputConsole = Text(middleFrame)
self.inputConsole.insert(INSERT,"Data recieved from Serial:")
self.inputConsole.config(width=100,height=20)
self.inputConsole.pack(side=LEFT,padx=20,pady=20)
#blah blah blah, insert a bunch of stuff (buttons etc.) here:
#The following lines define the functions to be called when the buttons are pressed.
def engineFire(self,engineUse,pwm):
RXSerial='this should pop up in the text called inputConsole'
print RXSerial
self.inputConsole.insert(INSERT, RXSerial)
---------------------------------------------------
so yeah, basically RXSerial is a string (that I have checked that is working, the print RXSerial line successfully prints when called by a button. The problem is that the self.inputConsole.insert(INSERT,RXSerial) line is not working. Can anybody please help? I have tried a bunch of combinations of stuff but cant seem to get it working. Thank you.
If you're trying to insert the text from another thread it may fail to work. Also, if at some point you configured the text widget to be in the disabled state then inserting will fail. If that's the case (widget is disabled), setting the state to "normal" temporarily will solve the problem.
Without more information it's impossible to say for sure.

Trying to produce monospaced output in pyqt browser

I have modified a short piece of pyqt code to produce real-time rendering of a user's expression. I have used sympy's pretty-printing function for this, however the output does not appear correctly as the QTextBrowser uses a proportional rather than a monospaced font.
As a beginner I would also welcome any other thoughts you had on the code.
Many thanks and best wishes,
Geddes
from __future__ import division
import sys
import sympy
from PyQt4.QtCore import *
from PyQt4.QtGui import *
class Form(QDialog):
def __init__(self, parent=None):
super(Form, self).__init__(parent)
self.browser = QTextBrowser()
self.lineedit = QLineEdit("please type an expression")
self.lineedit.selectAll()
layout = QVBoxLayout()
layout.addWidget(self.browser)
layout.addWidget(self.lineedit)
self.setLayout(layout)
self.lineedit.setFocus()
self.connect(self.lineedit, SIGNAL("textChanged (const QString&)"),self.updateUi)
def updateUi(self):
text = unicode(self.lineedit.text())
for z in range(0,9):
text = text.replace('x'+str(z),'x^'+str(z))
text = text.replace(')'+str(z),')^'+str(z))
text = text.replace(str(z)+'x',str(z)+'*x')
text = text.replace(str(z)+'(',str(z)+'*(')
try:
self.browser.append(sympy.printing.pretty(sympy.sympify(text)))
self.browser.clear()
self.browser.append(sympy.printing.pretty(sympy.sympify(text)))
except:
if text=='': self.browser.clear()
app = QApplication(sys.argv)
form = Form()
form.show()
app.exec_()
You should be able to change the font with setFontFamily.
Concerning your code: I haven't really worked with PyQt yet (only some hacks like the font family in qbzr...), so I can't tell you if everything is okay. But the following is not a good idea:
except:
if text=='': self.browser.clear()
Never catch all exceptions with except:. This will also catch BaseExceptions like SystemExit, which shouldn't be caught unless you have a reason to do so. Always catch specific exceptions, or if you're at the highest level (before the unhandled exception handler is executed) and want to log errors, rather use except Exception: which will only handle exceptions based on Exception.
if text=='' - I think if not text is more "pythonic".
QTextBrowser inherits QTextEdit, so you can use the setCurrentFont(QFont) method to set a monospace font.
self.browser = QTextBrowser()
self.browser.setCurrentFont(QFont("Courier New")) #Or whatever monospace font family you want...
As for general comments on style, there's probably a way do change your text replacement stuff in updateUi() to regex, but I can't be sure without seeing sample data to figure out what you're trying to do.
Also, you should probably refactor
try:
self.browser.append(sympy.printing.pretty(sympy.sympify(text)))
self.browser.clear()
self.browser.append(sympy.printing.pretty(sympy.sympify(text)))
except:
if text=='': self.browser.clear()
Into something more like:
self.browser.clear()
try:
self.browser.append(sympy.printing.pretty(sympy.sympify(text)))
except:
if text=='': self.browser.clear()
Except probably catching the actual Exception you're expecting.
EDIT
Here's something for the equation normalizing it looks like you're trying to do, it works with lowercase a-z and real numbers:
def updateUi(self):
text = unicode(self.lineedit.text())
text = re.sub(r'(\d+)([\(]|[a-z])',r'\1*\2',text) #for multiplication
text = re.sub(r'([a-z]|[\)])(\d+)',r'\1^\2',text) #for exponentiation
The first pattern looks for 1 or more digits \d+ followed by an open parenthesis, or a single letter a-z [\(]|[a-z]. It uses parentheses to capture the digit part of the pattern and the variable part of the pattern, and inserts a * between them. \1*\2.
The second pattern looks for a variable a-z or a close parenthesis [a-z]|[\)], followed by one or more digits \d+. It uses the grouping parentheses to capture the digit and the variable again, and inserts a ^ between them \1^\2.
It's not quite perfect (doesn't handle xy --> x*y) but its closer. If you want to make a full computer algebra system you'll probably need to build a dedicated parser :)

Categories

Resources