Get the actual Qt window title, properly replacing the [*] placeholder - qt

I need to get the visible title of a Qt top level window (or MDI subwindow), because I want to list window titles in different places just like they're visible for the user.
Consider a program that supports multiple top level editor windows (or an MDI area with similar purposes) that should list the titles of those windows, like a menu or an internal "window manager".
If I want to list those windows and also support the [*] placeholder for the windowModified property, their windowTitle() will return that annoying placeholder no matter of their state.
Unfortunately, the windowTitle feature is a bit abstract, for the following reasons:
due to the windowModified feature, it always returns the placeholder if it's set;
the [*] placeholder can be "escaped" with multiple, even occurrences, in order to actually display [*] in the window title: Title [*][*] will always be shown as Title [*] no matter the value of the windowModified property;
if the windowTitle property is an empty string (the default), it falls back to the windowFilePath property, which not only make it always include the [*] placeholder, but could also behave oddly in the rare case that property contains the [*] placeholder; while I realize that this is a very odd (and somehow irresponsible, assuming the system actually supports it) situation, I still want a reliable way to get the currently resulting window title, even in those rare (though "wrong") situations;
Is there a way to get the real title that Qt sets for the window, considering the above?

The best approach for top level windows (not MDI subwindows) is to use QWindow::title:
This property holds the window's title in the windowing system
The window title might appear in the title area of the window
decorations, depending on the windowing system and the window flags.
It might also be used by the windowing system to identify the window
in other contexts, such as in the task switcher.
How to obtain the QWindow?
If you already know the QWidget, you can use QWidget::windowHandle. Note that the QWindow object is only available for native widgets (f.ex. top level widgets, but not for MDI subwindow).
Another approach is to directly query for all the top level windows using QGuiApplication::topLevelWindows
MDI subwindow support?
As those MDI subwindows are not top level windows, the QWindow doesn't exists. So, this approach doesn't work in that case. Possible solutions are:
See #musicamente's answer, mimicking the Qt placeholder replacement procedure.
Create a Qt bug report to expose the resolved window title or alter the Qt source code yourself to do so and distribute it with your application.

There is no absolute and certain way to get the title that the OS will finally show in the title bar of a top level window.
As explained in the windowTitle documentation, some systems might support displaying the applicationDisplayName. Some highly customizable (Linux) OS might show an altered version of the provided title. There is almost no way to get the "final", displayed title, unless you want to dig into specific OS modules that interface with the Window Manager (and that might not be enough anyway, due to the high level of customization possible on *nix systems).
Considering that what's relevant for the OP is the "internal" window title (what Qt finally "relays" to the system), the solution is to implement what Qt actually does internally with qt_setWindowTitle_helperHelper().
Be aware that the Qt implementation is not perfect. There are some odd cases when specific combinations of the placeholder string are used. For instance:
using [*] [*] [*] as window title results in "[*]" being shown for an unmodified window and "* [*] *" otherwise;
with [*] [*][*] [*], the unmodified window title is " [*] [*]" (note the leading space) and the other is "* [*]* [*]"
While, as said above, the Qt implementation is far from perfect, what we're interested into is the actual window title relayed to the OS, so we must adhere to it, since the visual result is the important aspect, no matter whether it's "correct" or not.
Finally, remember that this implementation might become invalid in the future, in case Qt developers decide to change this behavior (and, I believe, they should).
The following code is a simple function that will return the actual window title relayed to the OS for a give widget, which can be used for any situation in which the visible title has to be displayed:
def realWindowTitle(widget):
title = widget.windowTitle()
placeHolder = '[*]'
if not placeHolder in title:
return title
phSize = len(placeHolder)
style = widget.style()
if (widget.isWindowModified()
and style.styleHint(
style.SH_TitleBar_ModifyNotification, None, widget)
# for PyQt6 or full Enum support use
# style.StyleHint.SH_TitleBar_ModifyNotification
):
replaceHolder = '*'
else:
replaceHolder = ''
index = title.find(placeHolder)
while index != -1:
index += phSize
count = 1
while title.find(placeHolder, index) == index:
count += 1
index += phSize
if count % 2: # odd number of [*] -> replace last one
lastIndex = title.rfind(placeHolder, 0, index)
title = (title[:lastIndex]
+ replaceHolder
+ title[lastIndex + phSize:])
index = title.find(placeHolder, index)
# return "escaped" sequences of the remaining double placeholders
return title.replace('[*][*]', placeHolder)

Related

Looking for example of how to display text in an NSWindow programmatically?

I am trying to display text in a HUD style semi-transparent window. I have got the code for the window all set up, but I have been scouring the documents for two days now and haven't come up with a way that works to actually display text in the window. Since I am using AppleScriptObjC in Script Debugger, and not Xcode, I'd rather do this programmatically and not have to switch to Xcode and use IB. (I did spend some time messing around with IB, but it is not very intuitive to be honest. So I thought I would check this form before going through the guides on how to get started using IB).
So I was given some advice to "create an NSTextField and add it to your window's contentView". So I have tried many different set ups of trying to init a NSTextField (And NSTextView), and I may have been able to get that part correct, but getting the text to actually display in the window has been a bigger challenge than I expected. I have included a code snippit of the code I am using to generate the window.
tell (NSWindow's alloc()'s ¬
initWithContentRect:{{theWidth, theHeight}, {640, 480}} ¬
styleMask:NSBorderlessWindowMask ¬
backing:NSBackingStoreBuffered ¬
defer:true)
setOpaque_(yes)
setAlphaValue_(0.5)
setBackgroundColor_(NSColor's grayColor())
setReleasedWhenClosed_(yes)
setExcludedFromWindowsMenu_(yes)
orderFrontRegardless()
delay 1
|close|()
end tell
My hope is to be able to get an NSText View in that Window in order to display some text in it. So far I haven't come close. The errors I generally get are about "unrecognized selector sent to instance". So it is pretty obvious that I am doing something wrong. I hope there is an easy way to accomplish this that I haven't yet come across.
It sounds like there isn't a target for some of the methods. In a tell statement, usually the target is implied, but sometimes AppleScript can't figure it out. You also don't get the newer method syntax, so I've had better luck just specifying the target for everything - also note that object properties can usually be set directly instead of using their setter method.
I can't tell from your snippet, but you also need to add the textView to the window's contentView, for example:
use AppleScript version "2.4" -- Yosemite (10.10) or later
use framework "Foundation"
use scripting additions
# create a text view
tell (current application's NSTextView's alloc's initWithFrame:{{20, 20}, {600, 440}})
set theTextView to it
end tell
# create a window
tell (current application's NSWindow's alloc()'s ¬
initWithContentRect:{{200, 600}, {640, 480}} ¬
styleMask:(current application's NSBorderlessWindowMask) ¬
backing:(current application's NSBackingStoreBuffered) ¬
defer:true)
set theWindow to it
set its opaque to true
set its alphaValue to 0.5
set its backgroundColor to (current application's NSColor's grayColor)
set its releasedWhenClosed to true
set its excludedFromWindowsMenu to true
end tell
theWindow's contentView's addSubview:theTextView
theTextView's setString:"this is a test"
theWindow's orderFrontRegardless()
delay 5
theWindow's |close|()

Qt: how to save QTextEdit contents with custom properties

I have a text editor (QTextEdit). Some words in my editor contains additional information attached (namely, two corresponding integer positions in wave file for that word).
They are stored in Python object as custom properties for QTextCharFormat objects (I attach them with code like this: self.editor.textCursor().setCharFormat(QTextCharFormat().setProperty(MyPropertyID, myWordAttachment) )
Unfortunately, if I save my document to html, all of that additional formatting is lost.
So, I want to perform simplest task: to save my document with all of it's formatting,including myWordAttachment (and to load it from disk).
Am I right that Qt5 doesn't have something ready for it, and I have to write all that document's serialization code by myself? (I still hope that where is simple function that did the job)
1.you loop your text every character.
2.and you catch the character and its charFormat()
3.and you get the properties.
4.Because the properties are eventually a value of something, int,str,...
So you get the properties by charFormat().property(1),(2),(3)... or properties()
5.The most important thing is the character's position & the range.You get the position during the 1th loop.
6.When you catch the CharFormats, you insert into something hashable object like list.
& and you don't forget to insert the CharFormats position.
6.you save your document and the position & properties.
My suggestion for your solution.
1.you can get characterCount() by the QTextDocument object.
2.you loop the range of the characterCount()
3.Before doing it, you make a QTextCursor object.
4.you set the textcursor at the first position.(movePosition method & Start moveoperation & KeepAnchor flag)
5.you move the cursor to right one character & Another.
6.you check the character's charFormat() by tc.charFormat() and the tc.position()
7.But it is the time to Think twice. CharFormat is always the bunch of characters.
you probably get some characters of the same CharFormat().
You can prepare for it.I can Think about some way,but... you should set the QCharFormat objectType or propertyId() for specifing the QCharFormat in Advance(during editing your document).Why don't you set the texts into the properties for after saving & loading.I hope you manage to pass here during debugging & tring.
8.if you get a charFormat,and you check the objectType().
9.if the objectType() is the same as Before searched, you pass the search engine without doing anything.
10.The second important thing is that calls clearSelection() each searching.
11.You save your document() as it is html strings.and you save the charFormats() properties.
12.when you load your document(),the html sentence comes back.
and load the properties.
you make QTextCursor and setPosition( the property's position saved in advance.)
you move QTextCursor until the position and you select the target texts.
you adopt the charFormat properties again and the end.
Summary
The important thing how you specify the charFormat().
You can catch the charFormat without any problem.but the charFormat() is adopted in some range.So you must distinguish the range.
1.The targeted texts is set in the QTextCharFormat's property.
2.You have The QTextCursor pass during the same QTextCharFormat's object.
I can Think of them...
I Think it is some helps for you.

Retrieve different text from combo box in Qt Designer (pyqt)

this could sound strange and it is more a curiosity then a question.
I have a simple combobox with 2 elements in Qt Designer.
The 2 combobox elements are vertical and horizontal but for the script I'm writing I need to get only v or h.
Usually I easily do it with a loop like:
name = self.combbox.currentText()
if name == 'vertical':
name = 'v'
else:
name = 'h'
and that's ok.
I was just thinking if there is a way in Qt Designer to assign a kind of tag to the elements so the user sees the complete text but with the code it can be retrieved the tag.
Thanks to all
I don't believe you can do this with Qt Designer alone (see How can I add item data to QComboBox from Qt Designer/.ui file).
With some extra Python, though, you can add use setItemData() to add whatever extra data you want (How can I get the selected VALUE out of a QCombobox?) and retrieve it with itemData() and currentIndex().

Accessing unreal script variables from Kismet - UDK

I have almost 0 scripting experience with UDK, but I think what I'm trying to do is fairly simple. I want to define a variable in script that I can then access in Kismet.
This is what I have so far:
MyGameInfo.uc looks like this
class MyGameInfo extends UDKGame;
defaultproperties{
PlayerControllerClass=class'MyGameInfo.MyPlayerController'
}
event InitGame( string Options, out string Error )
{
// Call the parent(i.e. GameInfo) InitGame event version and pass the parameters
super.InitGame( Options, Error );
// Unreal Engine 3
`log( "Hello, world!" );
}
MyPlayerController.uc looks like:
class MyPlayerController extends UDKPlayerController;
var() localized string LangText;
defaultproperties{
LangText="asdfasdf";
}
Then, in Kismet I'm using Get Property, with player 0 as the target, attempting to get property LangText. I have the string output going to Draw Text (and yes, I made sure to set a font).
It looks like this:
I feel like I'm really close, but no text shows up in the Draw Text. Any ideas?
Also, why am I trying to do this? For localization purposes. As far as I can tell, there's no easy way in Kismet to use localized strings for Draw Text. My thinking is just to create a localized string for each piece of dialog and then call those strings from Kismet as needed.
You need to make sure you added a Font asset from the content browser in the DrawText properties, and check it is actually placed on the screen (try Offset 0,0 for centered text)
Also, I think that DrawText doesn't work in UTGAME - in case that's your gametype. It works in UDKGame.
And if you have ToggleCinematic mode enabled, then check Disable HUD isn't on.
Test the DrawText with a regular string first...
Try using Player Spawned event instead of Level Loaded, as it may fire too fast for the player to have been added in the game yet.

What determines sorting of files in a QFileDialog?

Users open files in our app through a QFileDialog. The order of the filenames is bizarre. What is determining the sorting order, and how can we make it sort by filenames, or otherwise impose our own sorting, perhaps giving it a pointer to our own comparison function?
The documentation and online forums haven't been helpful. Unless it's well hidden, there doesn't seem to be any sorting method, property, etc.
This is a primarily Linux app, but also runs on Macs. (I know nothing about Mac.)
Here is the juicy part of the source code:
QtFileDialog chooser(parent, caption, directory, filter);
/// QtFileDialog is our class derived from QFileDialog
chooser.setModal(true);
chooser.setAcceptMode(acceptMode);
chooser.setFileMode(fileMode);
QStringList hist = chooser.history();
chooser.setHistory(hist);
/* point "x" */
if(chooser.exec()) {
QStringList files = chooser.selectedFiles();
...blah blah blah...
From one of the answers, I tried an evil experiment, adding this ill-informed guesswork code at "point x":
QSortFilterProxyModel *sorter = new QSortFilterProxyModel();
sorter->sort(1); // ???
chooser.setProxyModel(sorter);
But this crashed spectacularly at a point about 33 subroutine calls deep from this level of code. I admit, even after reading the Qt4 documentation and sample code, I have no idea of the proper usage of QSortFilterProxyModel.
Are you using QFileDialog by calling exec()? If you are, you should have a button to switch the view to Detail View. This will give you some column headers that you can click on to sort the files. It should remember that mode the next time the dialog opens but you can force it by calling setViewMode(QFileDialog::Detail) before calling exec().
An alternative is to call the static function QFileDialog::getOpenFileName() which will open a file dialog that is native to the OS on which you are running. Your users may like the familiarity of this option better.
Update 1:
About sort order in screen cap from OP:
This screen capture is actually showing a sorted list. I don't know if the listing behaviour is originating from the Qt dialog or the underlying file system but I know Windows XP and later do it this way.
When sorting filenames with embedded numbers, any runs of consecutive digits are treated as a single number. With the more classic plain string sorting, files would be sorted like this:
A_A_10e0
A_A_9a05
Going character by character, the first 1 sorts before the 9.
.. But with numerical interpretation (as in Windows 7 at least), they are sorted as:
A_A_9a05
A_A_10e0
The 9 sorts before the 10.
So, the sorting you are seeing is alphabetical with numerical interpretation and not just straight character by character. Some deep digging may be required to see if that is Qt behaviour or OS behaviour and whether or not it can be configured.
Update 2:
The QSortFilterProxyModel will sort the strings alphabetically by default so there is not much work to using it to get the behavior you are looking for. Use the following code where you have "point x" in your example.. (you almost had it :)
QSortFilterProxyModel *sorter = new QSortFilterProxyModel();
sorter->setDynamicSortFilter(true); // This ensures the proxy will resort when the model changes
chooser.setProxyModel(sorter);
I think what you need to do is create a QSortFilterProxyModel which you then set in your QFileDialog with QFileDialog::setProxyModel(QAbstractProxyModel * proxyModel)
Here are some relevant links to the Qt 4.6 docs about it.
http://doc.trolltech.com/4.6/qfiledialog.html#setProxyModel
http://doc.trolltech.com/4.6/qsortfilterproxymodel.html#details
I don't think it depends upon the implementation of Qt libraries... But upon the Native OS implementation..
For example in Windows,
if you use QFileDialog, it will display the Files and Directories by Name sorted.. It is the same when used in other applications. In the sense that, if you try to open a file through MS- Word, it indeed displays the Files and directories as Name sorted by default..
And am not sure about other environments since am not used to them...
But in Windows, you can change the sorted order by right-click in the area of Files and Directories display and can select the options you like.. For e.g like Name,size,type, modified... And also which is similar, when you use an MS-Word application...
So, I believe it does depend on the Native OS implementation and not on QFileDialog's...

Resources