How to add the UIA ExpandCollapse pattern in Qml - c++

I'm using http://accessibilityinsights.io/ to make sure my QML application passes Microsoft requirements for accessibility.
There's only one error that I couldn't resolve.
Qml ComboBoxes don't have the ExpandCollapse pattern.
Code to reproduce:
ComboBox {
model: ["First", "Second", "Third"]
}
Accessibility Insights says "An element of the given ControlType must support the ExpandCollapse pattern. Section 508 502.3.10
And "How to fix":
1. Make sure the element has the appropriate ControlType property for its function.
2. If the current ControlType is correct, modify the element to support the ExpandCollapse pattern.
StackOverflow couldn't help me. Google couldn't help me (I tried looking everywhere...)
So I went to Qt's source code.
I found this: qt-everywhere-src-6.2.1\qtbase\src\plugins\platforms\windows\uiautomation\qwindowsuiamainprovider.cpp
And here's the part that was interesting:
case UIA_ExpandCollapsePatternId:
// Menu items with submenus.
if (accessible->role() == QAccessible::MenuItem
&& accessible->childCount() > 0
&& accessible->child(0)->role() == QAccessible::PopupMenu) {
*pRetVal = new QWindowsUiaExpandCollapseProvider(id());
}
Which means that there must be a MenuItem object (the qml combobox doesn't have that), nor a child that's a PopupMenu.
So I checked, and the ExpandCollapse pattern works fine in a menu (from QWidgets), but not in qml.
I couldn't change the combobox's role (Accessible.MenuItem), it doesn't register for some reason (perhaps because of the c++ backend)
I tried "hacking" this in qml, to see if it could work, with this:
MenuItem
{
text: "test"
Rectangle {
Accessible.role: Accessible.PopupMenu
visible:false // to make the state "collapsed" by default.
}
}
And ... it works. I have the pattern.
But obviously this isn't a combobox (not by name, not for accessibility, and not for functionality).
So here's my question: is there a way to maybe have my custom combobox to have the combobox Accessible.role, while having this structure (Accessible.MenuItem + Accessible.PopupMenu) to make qwindowsuiamainprovider.cpp add the ExpandCollapse pattern?
Or is the only way to find a way to either change qwindowsuiamainprovider.cpp, or override it or something?
I couldn't find any way to change it without recompiling Qt myself with this change (I would also have to check the license if I'm allowed to do it...)

Related

Disable native Next button in Qt installer framework

I have to disable standard next button, on my custom page via installscript.qs file.
I can disable my own button (that I created in .ui file) via .qs script like this: widget.myButton.setEnabled(false);
This man shows that native buttons represented as enumeration and I cannot disable them same way.
Controller Scripting manual page shows some interactions with native buttons. Like gui.clickButton(buttons.NextButton). I go through whole gui object man and don't found anything useful.
Qt installer framework has a native license check page with Next button logic that I need, but I have not found any samples that do it manually. (license page work because its default license page and it's logic inside framework as I understand).
Finally I found isComplete() method that can be useful for me, but it is for C++ API not for qs.
So how to disable native button via installscript.qs file?
In case someone else end ups here, I finally found a cleaner solution: a dynamic widget has a property complete that can be changed to enable and disable the "Next" button. Set it to false to disable the button.
Controller.prototype.DynamicMyWidgetCallback = function()
{
var currentWidget = gui.currentPageWidget();
if (currentWidget != null)
{
currentWidget.complete = false
}
}
The only solution i had found is call installer.setValue("canContinue" "false");
Then connect page entered event using gui.pageById(QInstaller.TargetDirectory).entered.
connect(Component.prototype.targetPageEntered);
In targetPageEntered check our value:
Component.prototype.targetPageEntered = function () {
if (installer.value("canContinue") != "true") {
gui.clickButton(buttons.BackButton);
QMessageBox.information("someid", "Installer",
"You must do smth to continue", QMessageBox.Ok);
}
}
Of course you need to change the installer.value when user complete required actions.

Taking data from a Dialog in Qt and using it in a Ui

So I'm making a text editor using Qt and right now I have a button that opens a dialog called "Format text". I want it to work kind of like the dialog in notepad called "font" where you select a few text attributes from some drop down lists and it shows you what your text will look like. Right now I have it working where you can select the font style, font color, and font size and hit preview and it shows you in a box in the dialog what your text will look like. However, I have a button called "okay" which is supposed to change the highlighted text or the text you are about to type, but I can't figure out how to display those changes on the main window. The .ui files are private and a lot of the already made functions and pointers are the same in every ui file so if I change the ui file to pubic I have to change a whole bunch of things. Can anyway give me a simple answer? I'm trying to do this with as little confusion as possible. More coding and less confusion is better than less coding and more confusion for someone of my skill level. Sorry that this is all one giant paragraph and that I didn't provide any code, but I didn't think the code was necessary, however if you do need some of the code i'd be happy to share it.
Thank you for your help and your time. I hope you all have a nice evening.
QDialog have a signal called finished(), you can connect this signal with your slot. To accomplish your work, pass a QSettings or for simplicity QStringList to dialog settings (responsible for changing font, color ...), the QStringList will save user defined settings, after closing the dialog, iterate through QStringList member to alert Main window.
A pseudo code will look like this
Class Editor:
Editor::Editor()
{
TextSettings textSettings;
textSettings.setSettings(settings); // settings is a member
connect(textSettings, &finished(int)), this, SLOT(alertEditor(int)))
}
Editor::alertEditor(int s)
{
if(s == 0)
{
for (int i = 0; i < settings.size(); ++i)
settings.at(i).toLocal8Bit().constData(); // extract various user settings
}
}
Class TextSettings:
TextSettings::TextSettings(QStringList settings)
{
settings << ui->combobox->currentItem(); // font name as example
}

Change C++ model with QML

I want to extend the example called "Object ListModel Example" from Qt documentation
(you can get it on http://qt-project.org/doc/qt-4.8/declarative-modelviews-objectlistmodel.html).
I am trying to add a simple GUI functionality: a menu item that changes the content
(i.e. name) of the first data item in the model. Something like this:
MenuItem {
text: "Item 123"
onClicked: {
myModel.setProperty(0,"name","Item 123") //this gives me error
}
}
I am able to create a menu in QML but I cannot find the correct way to make changes in the model.
Btw, what is a difference between setContextProperty and qmlRegisterType (only the first one is used in this example but many other examples include the second one).
That kind of model is really not suitable for modification. There is no way for the view to be notified of changes. A better option is to use a QAbstractItemModel: http://qt-project.org/doc/qt-4.8/declarative-modelviews-abstractitemmodel.html
A simpler way to use a QAbstractItemModel is via QStandardItemModel: http://qt-project.org/doc/qt-4.8/qstandarditemmodel.html
setContextProperty() adds a single named property to the context. qmlRegisterType() registers a QObject-derived type with the QML engine, allowing it to instantiate that type. For example, the QDeclarativeItem type is registered with the engine as "Item", which is how the engine knows what to create when Item {} appears in QML code.

Using the GroupBoxes in Qt

I'm a student programmer and I am using Qt to build a GUI application. I'm trying to ensure that some check boxes are checked in order to proceed. These check boxes enable or disable the group box itself and are part of the QGroupBox class. Accepted combinations could be either or both. The problem I am running into is getting the boolean value(at least that's what I think it is) from the QGroupBox member function QGroupBox::setChecked(bool) and use it to determine whether or not to display an error message. I have tried several methods and reference Qts documentation hoping for a good example. Because the QGroupBox I'm trying to use is a member of my ui class I tried creating a new instance of QGroupBox and setting it to the values of the ui. Then; using an if statement, find out whether or not the boxes are check or not. Here's my code for this:
QGroupBox activeParticleInjection = ui->groupBoxParticleInjection;
QGroupBox activeFluidInjection = ui->groupBoxFluidInjection;
if (activeParticleInjection::setChecked(false) && activeFluidInjection(false));
{
QMessageBox noInjectionSelectedError;
noInjectionSelectedError.setText("Error: No injection type selected");
noInjectionSelectedError.exec();
}
else
{
transData.particleInjectionActive = activeParticleInjection::setChecked();
transData.fluidInjectionActive = activeFluidInjection::setChecked();
This doesn't work; starting with the way I'm trying to pass the Ui properties to the new instance of QGroupBox. I know that is question is relatively generic question but I tried passing the ui checkbox directly and that caused even more issues. I looked through the documentation and that led me to the way im trying to do it know; with no luck. I was hoping for some feedback on a better method of handling QGroupBox. Being a student sometimes its hard to see the answer especially when dealing with such unique members as the ones put together in QT.
Prior to changes I was using this method to build this process; and I received errors for the way my if parameters were setup. Compile error was : no matching function for call to 'QGroupBox::isChecked(bool)'
if (ui->groupBoxFluidInjection->isChecked(false) && ui->groupBoxParticleInjection->isChecked(false));
{
QMessageBox noInjectionSelectedError;
noInjectionSelectedError.setText("Error: No injection type selected");
noInjectionSelectedError.exec();
}
else
{
transData.particleInjectionActive = ui->groupBoxParticleInjection->isChecked();
transData.fluidInjectionActive = ui->groupBoxFluidInjection->isChecked();
}
I have been using these sites for most help:
QGroupBox
QCheckBox
You're mixing several things:
The QGroupBox instances in ui are pointers, so you must assign them to a QGroupBox* (pointer), not a QGroupBox (object on the stack).
:: is used with methods only if the method you call is static (class method), which is not the case here.
setChecked() is a setter setting the checked state of the group box. It doesn't return anything (void), so you cannot use them as conditions. What you want there is the getter bool QGroupBox::isChecked().
Your code snippet cleansed:
QGroupBox* activeParticleInjection = ui->groupBoxParticleInjection;
QGroupBox* activeFluidInjection = ui->groupBoxFluidInjection;
if (!activeParticleInjection->isChecked() && !activeFluidInjection->isChecked())
{
QMessageBox::critical(this, tr("Error"), tr("No injection type selected"));
}
else
{
transData.particleInjectionActive = activeParticleInjection->isChecked();
transData.fluidInjectionActive = activeFluidInjection->isChecked();
}
Not really sure what you tried to do in your code, but that's actually a lot easier to achieve. Also don't try to create copies (which you do in your example). Work with references or pointers in that case!
QGroupBox group("my group box"); // of course this might be a class member, too
group.setCheckable(true);
// do other things...
if(group.isChecked())
{
// do whatever if it's checked
}
else
{
// do stuff if it isn't checked
}
To check for at least one of multiple groups (or check boxes) being checked:
if(group1.isChecked() || group2.isChecked())

Using images in QListWidget, is this possible?

I am using QT to create a chat messenger client. To display the list of online users, I'm using a QListWidget, as created like this:
listWidget = new QListWidget(horizontalLayoutWidget);
listWidget->setObjectName("userList");
QSizePolicy sizePolicy1(QSizePolicy::Preferred, QSizePolicy::Expanding);
sizePolicy1.setHorizontalStretch(0);
sizePolicy1.setVerticalStretch(0);
sizePolicy1.setHeightForWidth(listWidget->sizePolicy().hasHeightForWidth());
listWidget->setSizePolicy(sizePolicy1);
listWidget->setMinimumSize(QSize(30, 0));
listWidget->setMaximumSize(QSize(150, 16777215));
listWidget->setBaseSize(QSize(100, 0));
listWidget->setContextMenuPolicy(Qt::CustomContextMenu);
Users are shown by constantly refreshing the list, like this: (Note: There are different channels, with different userlists, so refreshing it is the most efficient thing to do, as far as I know.)
void FMessenger::refreshUserlist()
{
if (currentPanel == 0)
return;
listWidget = this->findChild<QListWidget *>(QString("userList"));
listWidget->clear();
QList<FCharacter*> charList = currentPanel->charList();
QListWidgetItem* charitem = 0;
FCharacter* character;
foreach(character, charList)
{
charitem = new QListWidgetItem(character->name());
// charitem->setIcon(QIcon(":/Images/status.png"));
listWidget->addItem(charitem);
}
}
This has always worked perfectly. The line that I commented out is the one I have problems with: my current goal is to be able to display a user's online status with an image, which represents whether they are busy, away, available, etc. Using setIcon() does absolutely nothing though, apparently; the items still show up as they used to, without icons.
I'm aware that this is probably not the way this function needs to be used, but I have found little documentation about it online, and absolutely no useful examples of implementations. My question is, can anybody help me with fixing this problem?
This is how you may conduct your debugging:
Try the constructor that has both icon and text as arguments.
Try to use that icon in another context to ensure it is displayable (construct a QIcon with same argument and use it elsewhere, e.g. QLabel!).
Use icon() from the QListWidgetItem to receive back the icon and then look at that QIcon.
Create a new QListWidget, change nothing, and ordinarily add some stock items in your MainWidget's constructor. See if the icons show up there.