问题
I am accessing to my own robots via wi-fi using a third party router.
I wrote a small application that automatically log-in to the router, navigate through the tab
of the router interface all using JavaScript
inside a QML
application.
The small problem I have is that I have to trigger a relays to turn on/off the robot and inside the router GUI I need to trigger a combobox
as shown in the print screen below. After clicking on the I/O
tab, the address of the router page is https://123.456.789.123:7878/admin/ACEmanagerX.html#
:

The corresponding html
is also shown below:

EDITS
Now in order to replicate the problem I have I deployed a very small website https://comboboxtest.netlify.com/ that carries only one combobox with the same name and same choice I am trying to trigger.
The problem is that I can't find an easy ways to trigger the relays either on or off.
The expected behavior would be: if it is OFF
(value 0) put it ON
(value 1 which is Drive Active Low) and vice versa.
If you copy/paste the code below and run it it will automatically open the website but, unfortunately, it does not change the combobox from the OFF
position to Drive Active Low
and vice versa.
import QtQuick 2.13
import QtQuick.Controls 2.13
import QtWebEngine 1.9
ApplicationWindow{
id: root
width: 1940
height: 1100
visible: true
property string cBox: "https://comboboxtest.netlify.com"
QtObject {
// Below property triggers the combo box of the relays evaluating the normally closed (NC) or
// normally opened (NO) circuit
property string get_normallyClosed_or_normallyOpened_comboBox: "
var comboBox = document.getElementsByName('859-2-2')[0];
comboBox.addEventListener('change', function (e) {
comboBox.options[0].selected = true;
if ('createEvent' in document) {
var evt = document.createEvent('HTMLEvents');
evt.initEvent('change', false, true);
sel.dispatchEvent(evt);
}
else {
sel.fireEvent('onchange');
}
});
sel.addEventListener('change', function (e) {
alert('changed');
});
".arg(cBox)
}
Timer {
id: timer
interval: 1000; repeat: false
onTriggered: view.runJavaScript(internals.get_normallyClosed_or_normallyOpened_comboBox)
}
WebEngineView {
id: view
anchors.fill: parent
onUrlChanged: {
console.log(url)
if(url === Qt.resolvedUrl("https://comboboxtest.netlify.com/"))
timer.running = true
}
onCertificateError: function(error) {
error.ignoreCertificateError();
}
Component.onCompleted: view.url = "https://comboboxtest.netlify.com"
}
}
What I tried so far
1) After going through this post I found out that it is very important to give time to the http
request to start. That is why I added interval: 20000
after entering in the I/O tab. However, that was not useful and the combobox wasn't triggered.
2) I used this source to help me figure out how to trigger the combobox via JavaScript
and that is exactly what I applied but I didn't see any value changed in the combobox.
3) I found this post which is very close to what I am doing, with the difference that here it was also used a Button
to trigger the combobox. But in my case I have no button.
I know I am close to have it working but there is something I am missing. Thank you for shedding light on this matter for solving the problem
回答1:
I came up with a working example for you. There is nothing tricky here really, just precise syntax, learning JavaScript, and especially paying attention to the warning messages Qt produces while running. I can't stress the latter enough -- if you can't see the console output, it's not even worth testing. Even the latest cleaned-up MRE generated console warnings which were easily remedied, after which the real issues became more apparent.
There are two primary changes. First the test for
if (url === Qt.resolvedUrl("https://comboboxtest.netlify.com/"))
was never true
. Pretty basic and easily determined with a console.log()
. Good way to compare URL to a string is with url.toString()
.
Other big change is the script which runs in the Web View/browser. I tried to annotate this a bit. Hopefully I understood the purpose correctly -- toggle the selection in the combo box to the opposite of what is currently selected, and fire the change
event. I'm not entirely sure what the original script code was trying to do (or why the index change was inside the even listener... it would never get changed that way?). Anyway, here's what my version looks like.
import QtQuick 2.13
import QtQuick.Controls 2.13
import QtWebEngine 1.9
ApplicationWindow{
id: root
width: 320
height: 200
visible: true
property string url: "https://comboboxtest.netlify.com/"
QtObject {
id: internals
// Below property triggers the combo box of the relays evaluating the normally closed (NC) or
// normally opened (NO) circuit
property string get_normallyClosed_or_normallyOpened_comboBox: "
var comboBox = document.getElementsByName('859-2-2')[0];
// Check that we found a target element.
if (comboBox) {
// Add event listener to verify that combo change event gets fired.
comboBox.addEventListener('change', function (e) {
console.log('Change event detected:', e);
});
// Get new option index by flipping the current selected index
var newIdx = (comboBox.selectedIndex + 1) % 2;
console.log(comboBox, comboBox.selectedIndex, newIdx); // debug
// set the new index
comboBox.selectedIndex = newIdx;
// fire change event
comboBox.dispatchEvent(new Event('change'));
}
else {
console.error('comboBox not found!');
}
";
}
Timer {
id: timer
interval: 1000; repeat: false
onTriggered: {
console.log("Triggered timer with ", view.url);
view.runJavaScript(internals.get_normallyClosed_or_normallyOpened_comboBox);
}
}
WebEngineView {
id: view
anchors.fill: parent
onUrlChanged: {
if (url.toString() === root.url)
timer.running = true
}
onCertificateError: function(error) {
error.ignoreCertificateError();
}
Component.onCompleted: view.url = root.url
}
}
来源:https://stackoverflow.com/questions/58964730/qt5-qml-how-to-handle-a-combobox-in-qml-via-javascript