Alternative to wxStaticText in wxPython? - python

I have a problem in which I update StaticText fairly often(once every second) and every time it updates, it tears the frame. This is very bothersome on Windows but on Linux it never happened. I tried doing TextCtrl Readonly but I get ugly boxes around text I was wondering if there was a better option for updating text in wxPython frequently that wouldn't tear the screen. Thanks in advance!

I wish I understood better what you meant by "tearing" the frame - I don't seem to have problems with changing StaticText values after a window is created (though sometimes it's necessary to call Layout on a Panel or Dialog).
However, if you're really just looking for read-only TextCtrl's without the "ugly boxes" you should use TextCtrl(style = wx.NO_BORDER | wx.TE_READONLY). The combination will give you what you want - what appears to be a StaticText, but that can't be user-edited and doesn't display a border. You'll also be able to select its value (which may or may not be an advantage).

Related

Why do people say "Don't use place()"?

I have been working on a note taking program for myself and it is going well however I have had a lot of problems with getting all my widgets placed where I want them using the .pack() or .grid() options.
After looking around I found that I could use the .place() option instead. Before I decided to use .place() I found countless forum post saying "don't use .place()!".
I was at a stand still with my other options so I decided to give .place() a try. It turns out .place() is exactly what I needed to fix my layout issues and I just don't understand why everyone is hating on .place() so much.
Is there something inherently wrong with .place()? Or do people just prefer to use .pack() and .grid() for some practical reason other than ease of use?
I'm not sure what evidence you have that says everyone says not to use place. I suspect if you're judging by stackoverflow posts, you're mostly reading my opinion a hundred times rather than a hundred different opinions.
I recommend against place mainly because it requires more work to make a UI that is responsive to changes in fonts, resolutions, and window sizes. While it's possible to write a GUI that uses place and is responsive to those things, it requires a lot of work to get right.
One advantage that both pack and grid have over place is that they allow tkinter to properly configure the size of the root and Toplevel windows. With place you must hard-code a size. Tkinter is remarkably good at making windows to be the exact right size without you having to decide on explicit sizes.
In addition, long term maintenance of applications that use place is difficult. If you want to add a new widget, you will almost certainly have to adjust every other widget. With grid and pack it's much easier to add and remove widgets without having to change the layout of all of the other widgets. If I've learned anything over years of using tk and tkinter is that my widget layout changes a lot during development.
place is mostly useful for edge cases. For example, if you want to center a single widget inside another widget, place is fantastic. Also, if you want to place a widget such that it is independent of other widgets, place is great for that too.
There's nothing really wrong with .place, although using grid and pack give you more maintainable code. If you want to add a feature then place would require you to alter loads of absolute placements to fit a button in, for example.
If you need to use it then use it, there's no real problem with it, it just isn't the most maintainable solution to many problems. As you say, it's a matter of preference and ease of use.
Edit: there's an excellent answer you can read about it here.

How to reliably append text to the end of a text box using wxPython?

Edit2: Solved! I have no idea what changed or why, but now even a RichTextCtrl appends reliably. I left the old message below, despite this.
So I'm writing a GUI in python using wxPython. One of the main elements of this GUI is a textbox.
Features I need:
The ability to reliably append text to the end of the textbox.
Prevent user editing the textbox
Vertical Scroll bar
Features I'd like:
User can select text even when more lines are being appended
Text color can be changed
With that in mind I tried to do use the RichTextCtrl provided by wxPython.
However there appears no way to reliably add text to the end of the text box. The AppendText method is not reliable. If I click a location in the textbox while several lines are being appended this way it is likely one or more of the lines will be inserted where-ever I moved the cursor.
Does anyone have any suggestions on how to reliably append text to a RichTextCtrl? I might be able to clear it and replace all of its text with new text every time I want to append something, but I fear the performance hit from this would be severe. If there is a different text control that would be more appropriate for this please suggest it.
Edit: Using a regular TextCtrl appends reliably. Still no luck with a RichTextCtrl.
AppendText works for me on Windows with wxPython 2.9. If you want to prevent the user from editing, you'll need to use the wx.TE_READ_ONLY style flag. To make a vertical scroll bar appear, add the wx.TE_MULTILINE flag too.
The wxPython demo shows how to change text color. Basically you programmatically select a range and set a style / font for that selection. Getting the ability to select text while appending may not be possible. You would probably have to set up some kind of buffer for the appends and append after the user finishes selecting or keep track of what the user is selecting, append and then reselect.

Scrolling in QScrollArea pyqt

How can I auto scroll for the scroll area? For example, when there is a new update instead of the view of the scroll area staying the same, I want to go down with the new text. Think of it as in a CMD console, when you type a command it autoscroll with the output.
I was just going to respond to the other answer, but I just didn't know the best way to phrase it in the space allotted.
QScrollArea's are very useful widgets to use when designing custom PyQt widgets - I use them often. Things like rollout widgets, card widgets, anything where you could be displaying multiple sub-widgets with the need for scrolling can be a very useful utility. I don't agree with the idea that a QScrollArea isn't much use on its own.
The QTextEdit answer solves the problem the developer was facing - but only because it so happens the question is really about that. If you're trying to scroll a text edit, go with that answer.
However, if you are searching for an answer to the actual question and come across this thread, then the way to scroll down a QScrollArea is by actually modifying the scrollbar's value.
area = QScrollArea(parent)
vbar = area.verticalScrollBar()
vbar.setValue(vbar.maximum())
If you want to scroll to particular areas or anything (like implementing the ensureCursorVisible) then you want to take the location on the area's widget that you want to scroll to, figure out the percentage of the height of it, and apply that value to the vertical scrollbar. (Pseudocode)
Use QTextEdit.moveCursor to set the location you want to scroll to, and then use QTextEdit.ensureCursorVisible to scroll to it:
textedit.moveCursor(QtGui.QTextCursor.End)
textedit.ensureCursorVisible()

wxPython panel redraw in windows

I am trying to make several different pages where I need to show different texts and buttons.
What I did was I created a panel, and then several sizers on it, and then in the next page, I destroyed the panel and recreated the panel again with different contents/sizers.
It worked well in Linux, but when I tried the same source in the windows, the first page was okay, but in the second page and onward, it seems the sizers were not applied.
I tried various .Update() and .Refresh(), but nothing seems working.
It seems only when I maximize the window the sizers get applied and the layout becomes normal.
(Again, after panel.Destory() and a new panel generation, the layouts are messed up again.)
How do I make two different "pages" (where I click on a button and it goes to the second page) with different contents and sizers in Windows?
Calling Layout on the widget's parent is the best way to do this is you are adding or destroying widgets. Sometimes you also need to call Refresh() to make it redraw too, although that might only be required when you're using Freeze/Thaw.
It seems there are better ways to do this, but panel.Layout() solved the problem for now. :)
I agree with using Layout(), but might I suggest just hiding the unused panel instead of destroying it? Using the Show()/Hide() functions of the sizer, you can add both side-by-side and just hide the unused panel instead of destryong it and recreating it each time?

Can you auto hide frames/dialogs using wxPython?

I would like to create an application that has 3-4 frames (or windows) where each frame is attached/positioned to a side of the screen (like a task bar). When a frame is inactive I would like it to auto hide (just like the Windows task bar does; or the dock in OSX). When I move my mouse pointer to the position on the edge of the screen where the frame is hidden, I would like it to come back into focus.
The application is written in Python (using wxPython for the basic GUI aspects). Does anyone know how to do this in Python? I'm guessing it's probably OS dependent? If so, I'd like to focus on Windows first.
I don't do GUI programming very often so my apologies if this makes no sense at all.
As far as I know, there's nothing built in for this.
When the window is hidden, do you want it completely invisible or can a border of a few pixels be showing? That would be an easy way to get a mouse hover event. Otherwise you might have to use something like pyHook to get system-wide mouse events to know when to expand your window.
The events EVT_ENTER_WINDOW and EVT_LEAVE_WINDOW might also be useful here to know when the user has entered/left the window so you can expand/collapse it.
Expanding/collapsing can just be done by showing/hiding windows or resizing them. Standard window functions, nothing fancy.
By the way, you might want to use wx.ClientDisplayRect to figure out where to position your window. That will give you a rectangle of the desktop that does NOT include the task bar or any other toolbars the user has, assuming you want to avoid overlapping with those things.
Personally, I would combine the EVT_ENTER_WINDOW and EVT_LEAVE_WINDOW that FogleBird mentioned with a wx.Timer. Then whenever it the frame or dialog is inactive for x seconds, you would just call its Hide() method.
I think you could easily just make a window that is the same size as the desktop then do some while looping for an inactivity variable based on mouse position, then thread off a timer for loop for the 4 inactivity variables. I'd personally design it so that when they reach 0 from 15, they change size and position to become tabular and create a button on them to reactivate. lots of technical work on this one, but easily done if you figure it out

Categories