I am a Python noob so I may be missing something here, but I have a problem with how a string is handled inside my program. When I display it, only the first character is displayed.
# some code
MessageBox = ctypes.windll.user32.MessageBoxA
# some other code
testString = self.statusBar1.GetStatusText(0)
# displays "azertyu"
MessageBox(None, "azertyu", 'COUCOU', 0)
# displays 'M'
MessageBox(None, testString, 'COUCOU3', 0)
# displays 'a'
MessageBox(None, testString[1:], 'COUCOU3', 0) #
#displays 'c'
MessageBox(None, testString[2:], 'COUCOU3', 0)
The full string is 'Machine' (it's actually longer than that).
How comes Python considers any character is the ending one and displays only one character at once ? Am I missing some Python basics here ?
PS. GetStatusText reference is available at http://www.wxpython.org/docs/api/wx.StatusBar-class.html#GetStatusText. I have tested GetStatusText with a very long string and it doesn't seem to cut texts.
MessageBoxA is the ascii version of the MessageBox win32 API. Your testString is probably a Unicode value, so the value being passed to MessageBoxA will end up looking like an array of bytes with a zero in every other index. In other words it looks like a character string with just one character terminated by a NULL character. I bet if you use str(testString) or switch to MessageBoxW then it will work as expected, however you really should be using wx.MessageBox or wx.MessageDialog instead.
If you are using wxPython, why are you trying to show a message box with ctypes? The wxPython package has its own message dialogs. See the following links:
http://wiki.wxpython.org/MessageBoxes
http://wxpython.org/docs/api/wx.MessageDialog-class.html
http://www.blog.pythonlibrary.org/2010/07/10/the-dialogs-of-wxpython-part-2-of-2/
The wxPython demo package (downloadable from the wxPython website) has examples of MessageDialog and GenericMessageDialog.
Try ctypes.windll.user32.MessageBoxW instead of ctypes.windll.user32.MessageBoxA:
import ctypes
ctypes.windll.user32.MessageBoxW(None, "Hello, world!", "Test", 0)
It's treating the testString as a list
In [214]: for x in "Machine":
.....: print x
.....:
M
a
c
h
i
n
e
Have you tried ?
MessageBox(None, [testString], 'COUCOU3', 0)
as it's as if MessageBox is expecting a list of txt, which might makes sense:
["DANGER", "Will Robinson"]
Would then give two lines of txt on your message.
PURE GUESSWORK
Related
The problem I'm trying to solve is to get a couple ch,att representing the character and the associated attribute currently displayed at some given position.
Now, when the displayed character is not a wide one (i.e. an ASCII character), the method .inch does the job up to masking correctly the results. The issue comes when the displayed character is wide. More precisely I know how to get the given character through .instr, however this function does not return any information about the attribute.
Since, as far as I know, there is no specific function to get the attribute alone, my first attempt was to use .inch, drop the 8 less significant bit and interpret the result as the attribute. This seemed to work to some extent but double checking I realized that reading greek letters (u"u\03b1" for instance) with no attribute in this way returns att = 11.0000.0000 instead of 0. Is there a better way to approach the problem?
EDIT, a minimal example for Python3
import curses
def bin(x):
out = ''
while x > 0:
out = str(x % 2) + out
x = x // 2
return out
def main(s):
s.addstr(1, 1, u'\u03b1')
s.refresh()
chratt = s.inch(1, 1)
att = chratt & 0xFF00
s.addstr(2, 1, bin(att))
s.refresh()
while True:
pass
curses.wrapper(main)
In curses, inch and instr is only for ascii characters as you suspected. "complex" or "wide" characters like characters from utf-8 have another system, as explained here on stackoverflow by one of the ncurses creators.
However, onto the bad news. They aren't implemented in python curses (yet). A pull request was submitted here and it is very close to merging (90%), so if you really need it then why not go contribute yourself?
And if that isn't an option, then you could try to store every change you make to your screen in a variable and then pull the wide characters from there.
Learning python through a book, and tkinter.END is used in a block of code without being explained
import tkinter
def count(text, out_data):
""" Update out_data with the total number of As, Ts, Cs, and Gs found in text."""
data = text.get('0.0', **tkinter.END**)
counts = {}
for char in 'ATCG':
counts[char] = data.count(char)
out_data.set('Num As: {0} Num Ts: {1} Num Cs: {2} Num Gs: {3}'.format(
counts['A'], counts['T'], counts['C'], counts['G']))
...
I've looked online, and I only run across examples of it, never mentioning it's function.
I tried help(tkinter) in a shell and got END = 'end' which wasn't very useful.
If more code is required, just let me know. Didn't want to post the entire code making you pointlessly read more for no reason.
It doesn't "do" anything. It is a constant, the literal string "end". In this context it represents the point immediately after the last character entered by the user. The function get on a text widget requires two values: a starting position and an ending position.
Note: in the line text.get('0.0', tkinter.END), '0.0' is invalid (though, tkinter graciously accepts it, and treats it the same as '1.0'). Text indexes are of the form line.character. Lines start counting at 1, characters start at zero. So, the first character is '1.0', not '0.0'.
It's just a constant.
The Python tkinter library is a wrapper around tk, so you'll want to reference the source documentation, which can be found at: http://www.tkdocs.com/tutorial/text.html#basics.
For your question, see the section on Retrieving the Text. In their Python example, they don't even use the constant:
thetext = text.get('1.0', 'end')
I am trying to update the last line in PyCharm's console. Say, I print a and then I want to change it to c. However, I encounter the following problem. When I run:
print 'a\bc'
it prints
a c
while the desired output (which is also what I see in the Windows console) is:
c
Is there a way to move the cursor back in PyCharm's console? or maybe delete the whole line?
This is not a bug, this is a limitation of the interactive console found both in PyCharm, and in the IDLE shell.
When using the command prompt of windows, or a linux shell - the \b character is interpreted as a backspace and implemented as it is being parsed - However, in the interactive console of PyCharm and IDLE the \b character and many others are disabled, and instead you simply get the ASCII representation of the character (a white space in most cases).
It's a known bug: http://youtrack.jetbrains.com/issue/PY-11300
If you care about this, please get an account on the bug tracker and upload the bug to give it more attention.
The \r works. I know this is ASCII Carriage Return, but i use this as a workaround
print("\ra")
print("\rc")
will yield in c in the console
By the way, backspace is a ASCII Character
I just ran into the same issue in PyCharm (2019.1) and stumbled on this post. It turns out that you can use the \b character if you use the sys.stdout.write function instead of print. I wasn't able to get any of the above examples working within PyCharm using the print function.
Here's how I update the last line of text in my code assuming I don't need more than 100 characters:
# Initialize output line with spaces
sys.stdout.write(' ' * 100)
# Update line in a loop
for k in range(10)
# Generate new line of text
cur_line = 'foo %i' % k
# Remove last 100 characters, write new line and pad with spaces
sys.stdout.write('\b' * 100)
sys.stdout.write(cur_line + ' '*(100 - len(cur_line)))
# ... do other stuff in loop
This should generate "foo 1", then replaced with "foo 2", "foo 3", etc. all on the same line and overwriting the previous output for each string output. I'm using spaces to pad everything because different programs implement the backspace character differently, where sometimes it removes the character, and other times it only moves the cursor backwards and thus still requires new text to overwrite.
I've got to credit the Keras library for this solution, which correctly updates the console output (including PyCharm) during learning. I found that they were using the sys.stdout.write function in their progress bar update code.
There are already some questions touching this but no one seems to actually solve it.
import pydoc
hlpTxt = pydoc.render_doc(help)
already does what I want! looks flawless when printed to the (right) console but it has those extra characters included:
_\x08_H\x08He\x08el\x08lp\x08pe\x08er\x08r
In Maya for instance it looks like its filled up with ◘-symbols! While help() renders it flawless as well.
Removing \x08 leaves me with an extra letter each:
__HHeellppeerr
which is also not very useful.
Someone commented that it works for him when piped to a subprocess or into a file. I also failed to do that already. Is there another way than
hlpFile = open('c:/help.txt', 'w')
hlpFile.write(hlpTxt)
hlpFile.close()
? Because this leaves me with the same problem. Notepad++ actually shows BS symbols at the places. Yes for backspace obwiously.
Anyway: There must be a reason that these symbols are added and removing them afterwards might work but I can't imagine there isn't a way to have them not created in the first place!
So finally is there another pydoc method I'm missing? Or a str.encode/decode thing I have not yet seen?
btw: I'm not looking for help.__doc__!
In python 2, you can remove the boldface sequences with pydoc.plain:
pydoc.plain(pydoc.render_doc(help))
>>> help(pydoc.plain)
Help on function plain in module pydoc:
plain(text)
Remove boldface formatting from text.
In python 3 pydoc.render_doc accepts a renderer:
pydoc.render_doc(help, renderer=pydoc.plaintext)
this piece of code is driving me crazy. I'm trying to print a help list for a program I'm writing. So I define a dictionary, where the keys are the words that the user might want to be clarified and the values are the descriptions of the words. Then I use a for... in... loop to print it all. To put it simple:
ERROR = '\x1B[1;31m ERROR!! \x1B[0m'
WARNING = '\x1B[1;33m WARNING! \x1B[0m'
SUCCESS = '\x1B[1;32m Operation successful! \x1B[0m'
ABORTED = '\x1B[1;33m Operation aborted! \x1B[0m'
help_descriptions = {'\x1B[34m NUMBERS \x1B[0m':'are the options you can take.',\
ERROR:'means you ran into and error and the program can\'t go on.',\
WARNING:'means that the data you entered might cause problems.',\
SUCCESS:'means that no run-time errors where encoutered.',\
ABORTED:'means you aborted a previous option, deleting\n the data associated.'}
def HelpMe():
print(70 * '~')
print(' HELP')
print(70 * '~')
for key in help_descriptions.keys():
print('%10s %s' % (key, help_descriptions.get(key)))
print(70 * '~')
The only thing that doesn't work is the %10s token. I mean, it does print the value of the key, but it does not puts extra spaces if needed. I've tried to run in an interactive section this piece of code
print('%10s' % 'foo')
and the output is right.
Does any of you have an idea of how make it work?
Additional info: I'm running Python 3 on a Linux machine running Ubuntu 11.04. This code is part of a custom module I've written to store some static text or simple functions that print text. So I import this module in the main application, it is not stand-alone.
Thank you in advance.
The problem is that those are at least 10 characters long: remember, the ANSI escape characters count. You could do any of the following:
Increase the field width until you get the width you want (since all of them seem to contain the same number of escape characters, this might work).
Strip the escape characters and use the result for padding.
Pad the labels (like "WARNING!") to the correct field width before adding the escape characters.
Any of these should achieve the desired effect.