I am trying to push notification to Jaws or NVDA when certain events occur.
These events can occur any time and any application widget can have the focus. They are not linked to user actions but to the controller events.
This is my try:
void announceNewMessageIfNeeded(){
if(QAccessible::isActive()){
QWidget* focusWidget = QApplication::focusWidget();
if(focusWidget != nullptr){
auto* accessibleInterface = QAccessible::queryAccessibleInterface(focusWidget);
accessibleInterface->setText(QAccessible::Name, "New Message");
auto *ev = new QAccessibleEvent(accessibleInterface, QAccessible::Alert);
QAccessible::updateAccessibility(ev);
}
}
}
I tried the above code with various little changes but I either do not have accesibility update or undesired access to nullpointers.
With debug logs, I know for sure that the focusWidget is correct (it points to the item having the currentFocus) and that announceNewMessageIfNeeded is called.
Any idea?
solution that seems to work:
if(QAccessible::isActive()){
QWidget* focusedWidget = QApplication::focusWidget();
if(focusedWidget != nullptr){
auto *ev = new QAccessibleValueChangeEvent(focusedWidget, "New Message");
QAccessible::updateAccessibility(ev);
}
}
Related
I'm trying to add quit confirmation message at OS shutdown according to this example:
https://doc.qt.io/qt-5/qsessionmanager.html#allowsInteraction
I interact with the user via QML interface. It is asynchronous, so I use slots/signals. And I use additional QEventLoop to stay inside of QGuiApplication::commitDataRequest call while interacting with the user.
The trouble is that after I shutdown OS (Windows 10) - my app prevents OS to shutdown and it's good, but its screen is just white, or contains old state without the confirmation dialog. I need to hide/restore window or change its size, or do some mouse clicks inside of it to force it repaint. When it repaint all is OK and my confirmation dialog is there.
Is this a bug? Is there a workaround?
This is the code I use:
void AppQuitConfirmationAtOsShutdownManager::onCommitDataRequest(
QSessionManager &m)
{
if (!m_ui->isConfirmationRequired())
return;
if (!m.allowsInteraction())
return;
bool isConfirmed = true;
QEventLoop loop;
qtconnect(m_ui.data(), &AppQuitConfirmationUiManager::confirmationResult,
&loop, [&](bool confirmed)
{
isConfirmed = confirmed;
loop.quit();
},
Qt::QueuedConnection);
m_ui->requestConfirmation();
loop.exec();
m.release();
if (!isConfirmed)
m.cancel();
}
I have an activity indicator on xaml page. Initially its IsVisible property is false. I have a button on page. When user click on button it calls a web service to get data. I change the value of IsVisible property to true before calling the service so that activity indicator starts to display on page and after successful calling of service I change its value to again false so that it doesn't show any more on page.
But it is not working. I know the actual problem. When we call the web service the UI thread gets block and it doesn't show the activity indicator.
How I can enable the UI thread when web service gets called so that activity indicator can show on page until we get the data?
Try making your webservice call into an async and await it.
Depending on how you've structured things you may have to use a TaskCompletionSource as the following example demonstrates.
In this example when the button is clicked, the button is made invisible, and the ActivityIndicator is set to IsRunning=True to show it.
It then executes your long running task / webservice in the function ExecuteSomeLongTask using a TaskCompletionSource.
The reason for this is that in our button click code, we have the final lines:-
objActivityIndicator1.IsRunning = false;
objButton1.IsVisible = true;
That stop the ActivityIndicator from running and showing, and also set the button back to a visible state.
If we did not use a TaskCompletionSource these lines would execute immediately after calling the ExecuteSomeLongTask if it was a normal async method / function, and would result in the ActivityIndicator not running and the button still being visible.
Example:-
Grid objGrid = new Grid()
{
};
ActivityIndicator objActivityIndicator1 = new ActivityIndicator();
objGrid.Children.Add(objActivityIndicator1);
Button objButton1 = new Button();
objButton1.Text = "Execute webservice call.";
objButton1.Clicked += (async (o2, e2) =>
{
objButton1.IsVisible = false;
objActivityIndicator1.IsRunning = true;
//
bool blnResult = await ExecuteSomeLongTask();
//
objActivityIndicator1.IsRunning = false;
objButton1.IsVisible = true;
});
objGrid.Children.Add(objButton1);
return objGrid;
Supporting function:-
private Task<bool> ExecuteSomeLongTask()
{
TaskCompletionSource<bool> objTaskCompletionSource1 = new TaskCompletionSource<bool>();
//
Xamarin.Forms.Device.StartTimer(new TimeSpan(0, 0, 5), new Func<bool>(() =>
{
objTaskCompletionSource1.SetResult(true);
//
return false;
}));
//
return objTaskCompletionSource1.Task;
}
You need to do your work in an asynchronous way. Or in other words: Use Asnyc & Await to ensure, that you UI works well during the call.
You can find more informations in the Xamarin Docs.
async and await are new C# language features that work in conjunction
with the Task Parallel Library to make it easy to write threaded code
to perform long-running tasks without blocking the main thread of your
application.
If you need further asistance, please update your question and post your code or what you have tried so far.
I'm trying to implement the following thing: when a specific button is clicked, a new dialog appears where the user has to enter some information and to check/uncheck some checkboxes. Then the user can either click "OK" or "Cancel".
If he clicks "OK" the information he entered is checked for correctness. If something is not correct the dialog should appear again with a warning message and the user should correct/re-enter the information. I would like the information the user entered to be stored. So, if the information is not correct, the dialog should not "reset" to the initial state but keep the information the user entered.
If the user clicks "Cancel" some standard values are used further.
I almost got a solution, but it is not working properly. When using my solution: when I enter a wrong information and click "OK" a warning appears and the information is stored and I can edit it. But if I enter wrong information again and click "OK" again, then the wrong information is accepted. Please see my code below.
QDialog dialog(this);
QFormLayout form(&dialog);
form.addRow((new QLabel("Please enter the three questions for the P835 test. \n"
"Questions one and two will be permuted, \n "
"question three will not. Below each question enter \n"
"the rating scale starting with the best rating and \n"
"separate the ratings with a comma.")));
QList<QLineEdit *> fields;
QLineEdit *lineEdit_Q1 = new QLineEdit(&dialog);
lineEdit_Q1->setText("Bitte bewerten Sie die Signalqualität!");
QString label_Q1 = QString("First question:");
form.addRow(label_Q1, lineEdit_Q1);
fields << lineEdit_Q1;
QLineEdit *lineEdit_Q1_answer = new QLineEdit(&dialog);
lineEdit_Q1_answer->setText("nicht verzerrt, leicht verzerrt, etwas verzerrt, ziemlich verzerrt, sehr verzerrt");
QString label_Q1_answer = QString("Rating first question:");
form.addRow(label_Q1_answer, lineEdit_Q1_answer);
fields << lineEdit_Q1_answer;
QDialogButtonBox buttonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, Qt::Horizontal, &dialog);
form.addRow(&buttonBox);
QObject::connect(&buttonBox, SIGNAL(accepted()), &dialog, SLOT(accept()));
QObject::connect(&buttonBox, SIGNAL(rejected()), &dialog, SLOT(reject()));
bool click = true;
int code = dialog.exec();
bool passed = true;
while (click == true){
passed = true;
if (code == QDialog::Accepted) {
// check if empty questions were entered
if (lineEdit_Q1->text() == "" || lineEdit_Q2->text() == "" || lineEdit_Q3->text() == "") {
QMessageBox msgBox;
msgBox.setText("An error occured while entering questions for the P835 test");
msgBox.setInformativeText("You can not enter empty questions! Please try again or click cancel to use the standard questions!");
msgBox.setIcon(QMessageBox::Warning);
msgBox.exec();
passed = false;
dialog.close();
dialog.exec();
break;
}
if (lineEdit_Q1_answer->text().split(",").size() != 5 || lineEdit_Q2_answer->text().split(",").size() != 5 || lineEdit_Q3_answer->text().split(",").size() != 5) {
QMessageBox msgBox;
msgBox.setText("An error occured while entering question ratings for the P835 test");
msgBox.setInformativeText("You have to enter exactly 5 ratings for each question! Please try again or click cancel to use the standard ratings!");
msgBox.setIcon(QMessageBox::Warning);
msgBox.exec();
passed = false;
dialog.close();
dialog.exec();
break;
}
if (oneFileCheckBox->isChecked() && multipleFilesCheckBox->isChecked()) {
QMessageBox msgBox;
msgBox.setText("An error occured while setting up the P835 test...");
msgBox.setInformativeText("You cannot check both boxes! Please select only one option for the files!");
msgBox.setIcon(QMessageBox::Warning);
msgBox.exec();
passed = false;
dialog.close();
dialog.exec();
break;
}
if (oneFileCheckBox->isChecked() == false && multipleFilesCheckBox->isChecked() == false) {
QMessageBox msgBox;
msgBox.setText("An error occured while setting up the P835 test...");
msgBox.setInformativeText("You have to select one file option!");
msgBox.setIcon(QMessageBox::Warning);
msgBox.exec();
passed = false;
dialog.close();
dialog.exec();
break;
}
if (passed == true) {
this->configMgr->setQuestions(lineEdit_Q1->text(), lineEdit_Q2->text(), lineEdit_Q3->text());
this->configMgr->setAnswers(lineEdit_Q1_answer->text(), lineEdit_Q2_answer->text(), lineEdit_Q3_answer->text());
if(oneFileCheckBox->isChecked() == true) {
this->configMgr->fileOption = 0;
}
if(multipleFilesCheckBox->isChecked() == true) {
this->configMgr->fileOption = 1;
}
QMessageBox msgBox;
msgBox.setText("Success!");
msgBox.setInformativeText("The questions and the question ratings have been set successfully!");
msgBox.setIcon(QMessageBox::Information);
msgBox.exec();
dialog.close();
click = false;
}
if (code == QDialog::Rejected) {
this->configMgr->setQuestions(Q1_std, Q2_std, Q3_std);
this->configMgr->setAnswers(Q1_std_answer, Q2_std_answer, Q3_std_answer);
QMessageBox msgBox;
msgBox.setText("Setting standard values...");
msgBox.setInformativeText("Standard questions and ratings will be set. Click on the P835 button again to set questions and ratings manually!");
msgBox.setIcon(QMessageBox::Information);
msgBox.exec();
dialog.close();
click = false;
}
}
if (code == QDialog::Rejected) {
this->configMgr->setQuestions(Q1_std, Q2_std, Q3_std);
this->configMgr->setAnswers(Q1_std_answer, Q2_std_answer, Q3_std_answer);
QMessageBox msgBox;
msgBox.setText("Setting standard values...");
msgBox.setInformativeText("Standard questions and ratings will be set. Click on the P835 button again to set questions and ratings manually!");
msgBox.setIcon(QMessageBox::Information);
msgBox.exec();
dialog.close();
click = false;
}
}
In this example code I only put one text box where the user has to enter some information. I have six text boxes and two checkboxes.
I hope you can help me! Thank you!
You should use validation with QDialog::done(int r) or a QWizard. Qt makes this task relatively easy if you take the time to study the examples and documentation on it, but it does take time to learn it the first time.
Validation with QDialog::done(int r)
http://www.qtcentre.org/threads/8048-Validate-Data-in-QDialog
void DataSourceDlg::done(int r)
{
if(QDialog::Accepted == r) // ok was pressed
{
if(nodeLineEdit->text().size() > 3) // validate the data somehow
{
QDialog::done(r);
return;
}
else
{
statusBar->setText("Invalid data in text edit...try again...");
return;
}
}
else // cancel, close or exc was pressed
{
QDialog::done(r);
return;
}
}
Note that by subclassing QDialog and managing the done method you can prevent the dialog from closing and display a message.
QWizard and QWizardPage
http://doc.qt.io/qt-5/qwizard.html#details
Using a QWizard is a little more work, but it is built around validation and ensuring the correct information is in the right boxes.
Basically you subclass QWizard and QWizard page, and then you implement validatePage() and some others methods and you follow the examples and it works flawlessly. This used to be included in Qt Solutions and it was opened up a few years ago.
http://doc.qt.io/qt-5/qtwidgets-dialogs-classwizard-example.html
http://doc.qt.io/qt-5/qtwidgets-dialogs-licensewizard-example.html
companyLabel = new QLabel(tr("&Company name:"));
companyLineEdit = new QLineEdit;
companyLabel->setBuddy(companyLineEdit);
emailLabel = new QLabel(tr("&Email address:"));
emailLineEdit = new QLineEdit;
emailLineEdit->setValidator(new QRegExpValidator(QRegExp(".*#.*"), this));
emailLabel->setBuddy(emailLineEdit);
postalLabel = new QLabel(tr("&Postal address:"));
postalLineEdit = new QLineEdit;
postalLabel->setBuddy(postalLineEdit);
registerField("details.company*", companyLineEdit);
registerField("details.email*", emailLineEdit);
registerField("details.postal*", postalLineEdit);
* makes a field mandatory. QRegExpValidator makes sure the email address has an # sign in the middle.
QValidator with QLineEdit
http://doc.qt.io/qt-5/qvalidator.html#details
http://doc.qt.io/qt-5/qtwidgets-widgets-lineedits-example.html
validatorLineEdit->setValidator(new QIntValidator(
validatorLineEdit));
validatorLineEdit->setValidator(new QDoubleValidator(-999.0,
999.0, 2, validatorLineEdit));
QLineEdit::setInputMask(QString)
http://doc.qt.io/qt-5/qlineedit.html#inputMask-prop
inputMaskLineEdit->setInputMask("");
inputMaskLineEdit->setInputMask("+99 99 99 99 99;_");
inputMaskLineEdit->setInputMask("0000-00-00");
inputMaskLineEdit->setText("00000000");
inputMaskLineEdit->setCursorPosition(0);
inputMaskLineEdit->setInputMask(">AAAAA-AAAAA-AAAAA-AAAAA-AAAAA;#");
Regular Expressions
RegEx is awesome. Learning it is extremely useful (IMHO). I really like the tools and cheatsheets provided by gskinner. http://regexr.com/
http://doc.qt.io/qt-5/qregexpvalidator.html#details
// regexp: optional '-' followed by between 1 and 3 digits
QRegExp rx("-?\\d{1,3}");
QValidator *validator = new QRegExpValidator(rx, this);
QLineEdit *edit = new QLineEdit(this);
edit->setValidator(validator);
Hope that helps.
I am trying to switch to a New window which gets displayed when I click on the Debt Pricing Template. But I am unable to do that as a result of which I am not able to proceed with further scripting... The problem is I am not able to know what should I pass in the switchTo.window() because Pricing Approval Gateway window displays and following is the HTML for the new window:
<*h1 class="pageType noSecondHeader">Pricing Approval Gateway<*/h1>
Following is the code:
LoginPage2.driver.findElement(By.linkText("TEST ORG")).click();
System.out.println("3.Select Dept pricing template button from the organization detail page.");
if(LoginPage2.driver.findElement(By.name("debt_pricing_template")).isDisplayed())
System.out.println("User should able to navigate to Dept pricing template and template display few question, user have answer these question for further navigation.");
LoginPage2.driver.findElement(By.name("debt_pricing_template")).click();
LoginPage2.driver.manage().timeouts().implicitlyWait(100, TimeUnit.SECONDS);
LoginPage2.driver.switchTo().window("bPageTitle");
Please advise what needs to be added?
I never used it because in my tests I am not using any new windows, but this should help:
Set<string> handlers = driver.getWindowHandles();
if (driver.getWindowHandles().size()>= 1){
for(String handler : handlers){
driver.switchTo().window(handler);
if (driver.getElement(By.tagName("h1")).contains("Pricing")){
System.out.println("Get focus on Popup window");
break;
}
}
}
else System.out.println("No windows founded!");
I am not quite sure with the h1 approach. So if it does not help, try before opening new window storing current window to String:
String mainWindow = driver.getWindowHandle();
Then click the link (or do something else as you are doing now) to open new window. Then to switch to the new window:
Set<string> handlers = driver.getWindowHandles();
for (String handler : handlers){
if (!handler.equals(mainWindow)){
driver.switchTo(handler);
break;
}
}
And then to switch back to original window just do:
driver.switchTo(mainWindow);
Ofcourse the driver variable is expected live instance of
WebDriver
driver.findElement(By.linkText("Go to Billing Summary")).click();
driver.findElement(By.linkText("01 Mar 2016")).click();
Thread.sleep(5000);
driver.findElement(By.linkText("AMS TAX")).click();
driver.findElement(By.linkText("00842")).click();
Set<String> instancewindow= driver.getWindowHandles();
Iterator<String> it = instancewindow.iterator();
String parent =it.next();
String child = it.next();
driver.switchTo().window(child);
driver.switchTo().frame("modalSubWindow");
driver.findElement(By.linkText("View More Vehicle Details>>")).click();
driver.switchTo().window(parent);
I'm looking at rehosting the workflow designer. I want to be able to run some code whenever the user adds an activity to the designer canvass. Is there an event that fires when the user adds an activity at design time? Or is there an event on the activity that I can consume? Thanks!
For anyone who might stumble onto this, here's what I figured out...
First off, when creating the workflow designer, you need to subscribe to the ModelChanged event.
_workflowDesigner = new WorkflowDesigner();
_workflowDesigner.Load(new Sequence());
ModelService ms = _workflowDesigner.Context.Services.GetService<ModelService>();
if (ms != null)
ms.ModelChanged += new EventHandler<ModelChangedEventArgs>(ms_ModelChanged);
My event handler looks like this...
void ms_ModelChanged(object sender, ModelChangedEventArgs e)
{
if (e.ItemsAdded != null && e.ItemsAdded.Count<ModelItem>() == 1)
{
ModelItem item = e.ItemsAdded.FirstOrDefault<ModelItem>();
var test = item.GetCurrentValue() as MyActivityType;
if (test != null && test.Id == null)
{
//do whatever initialization logic is needed here
}
}
}
I need to give credit to this source for pointing me in the right direction.
One thing to be careful of - when you move an activity within the model, two events are raised, a remove and an add. At this point, I don't need to worry about whether I'm adding or moving an activity as I can tell whether it has been initialized, but if you need to know whether something has really been added to the model, you might need to track both events.