I'm working on integrating T-Cube motor controller (http://www.thorlabs.de/newgrouppage9.cfm?objectgroup_id=2419) into the software based on Qt-4.8.1 package. Due to there is no manual or any sort of tutorial how to retrieve ActiveX object and how to call methods I did the following.
1) Looked through Windows registry looking for words similar to motor controller name. Found a candidate with CLSID "{3CE35BF3-1E13-4D2C-8C0B-DEF6314420B3}".
2) Tried initializing it in the following way (code provided is shortened, all result checks are removed in order to improve readability):
HRESULT h_result = CoInitializeEx(NULL, COINIT_MULTITHREADED);
pd->moto = new QAxObject();
initialized = moto->setControl( "{3CE35BF3-1E13-4D2C-8C0B-DEF6314420B3}" );
QString stri = browser->generateDocumentation();
obj->dynamicCall("SetHWSerialNum(int)", params);
QVariantList params;
params << 0;
params << 0.0;
int result = pd->moto->dynamicCall("GetPosition(int, double&)", params).toInt();
value = params[1].toFloat();
QVariantList params;
params << 0;
params << dist;
params << dist;
params << true;
int result = pd->moto->dynamicCall("MoveRelativeEx(int, double, double, bool)", params).toInt();
3) generateDocumentation() method gives perfect description of ~150 methods.
4) All dynamicCall() invocations cause "Error calling ...: Unknown error", where "..." is a first argument of dynamicCall() from the list generateDocumentation()'s given me.
5) If I insert into dynamicCall() any method which isn't presented in the documentation generated the output is different. So I suppose that methods in documentation generated really exist.
6) If I use #import directive and try calling directly avoiding QAxObject usage I see "mg17motor.tlh" file but none of interfaces described there contain any methods. So I can't use it directly as well. Is it normal?
I would be very much obliged for any advice.
You can find the ActiveX object using the OLE viewer. Then search for something like
APT.. or MG.. under all objects. Then find the parameter ProgID=MGMOTOR.MGMotorCtrl.1.
Now in Qt don't use QAxObject but QAxWidget. Then you get something like:
QAxWidget* aptMotor;
QVariant chanID = QVariant(0);
aptMotor = new QAxWidget();
aptMotor->setControl("MGMOTOR.MGMotorCtrl.1");
//Nice html documentation on available functions
QFile file("out.html");
file.open(QIODevice::WriteOnly | QIODevice::Text);
QTextStream out(&file);
out << aptMotor->generateDocumentation();
file.close();
aptMotor->setProperty("HWSerialNum",QVariant(83853493));
aptMotor->dynamicCall("StartCtrl");
aptMotor->dynamicCall("EnableHWChannel(QVariant)",chanID);
QThread::sleep(1); // Give it time to enable the channel
double pos(0);
aptMotor->dynamicCall("SetAbsMovePos(QVariant,QVariant)",chanID,QVariant(pos));
aptMotor->dynamicCall("MoveAbsolute(QVariant,QVariant,QVariant)",chanID,0);
aptMotor->dynamicCall("StopCtrl");
Related
I'm trying to create a simple "To Do list" app in QT Creator while coding the part that loads and saves the list from a file I get stuck on a problem.
If you enter a string like "Do my homework" the program threads the string as it should, but when you load the program again the save file got split in words. So it gets all the entries but each word separated ("Do", "my", "homework").
What is the solution? I tried working with 'char arrays' and 'getline' but they give me nothing but errors.
Here is my code for the save and load parts:
void MainWindow::LoadList(){
std::ifstream load_file("./data.bin");
char loader[255];
while (load_file >> loader){
QString Writer = QString::fromStdString(loader);
ui->lstTaskList->addItem(Writer);
}
}
void MainWindow::SaveList(){
std::ofstream save_file("./data.bin");
for (auto i = 0; i < ui->lstTaskList->count(); i++){
QString Saver = ui->lstTaskList->item(i)->text();
std::string saver = Saver.toStdString();
save_file << saver << std::endl;
}
}
Can anyone help me with this, please?
My thanks in advance...
The anwser was using QFile and QByteArray for me, I knew about QFile but it tries using basic "std" c++ till I learned more about QT.
I've a question that couldn't find anywhere. I have a QMap that's ignoring the QMap.insert(Key, Value) command. Here's the code:
//gets the selected problem index on the ProblemList
int selProblem = ui->tree_projects->currentItem()->data(0, Qt::UserRole).toInt();
//creates a new problem, sets its values and then replaces the old one on the ProblemsList variable
ProblemSets nProblem;
if(!problemsList.isEmpty()) //problemsList is an attribute of MainWindow
nProblem = problemsList.value(selProblem);
// some data collection that has been omitted because isn't important
// temporary maps that will carry the modifications
QMap<int, QString> nResName, nResType;
//data insertion into the maps
//these are fine
nResName.insert(fIdx, results_model->data(results_model->index(fIdx, 0)).toString());
nResType.insert(fIdx, results_model->data(results_model->index(fIdx, 1)).toString());
//replaces the old maps with the new ones
nProblem.SetProbResultsNames(nResName);
nProblem.SetProbResultsTypes(nResType);
//replaces the old problem with the new one
problemsList.insert(selProblem, nProblem); //this is the line that's doing nothing
}
That last line appears to be doing nothing! I've even tried to use
problemsList.remove(selProblem);
problemList.insert(selProblem, nProblem);
but got a similar result: the map not being inserted at the index selProblem. It got inserted, but with an outdated value - the same one of the deleted index -. I've checked on Debug and all the indexes and variables are correct, but when the .insert hits, nothing happens.
The most awkward thing is that this code is a copy/paste that I made from another method that I'm using that does similar thing, just changing the variable names, but that one works.
EDIT 1: This is the contents of nProblem, selProb and problemsList.value(selProblem)
Just before the Line:
problemsList.insert(selProblem, nProblem);
selProb: 0
nProblem:
ProbResultsNames: "NewRow0"
ProbResultsType: "Real"
problemsList.value(selProblem):
ProbResultsNames: non-existent
ProbResultsType: non-existent
After the line
problemsList.insert(selProblem, nProblem);
selProb: 0
nProblem:
ProbResultsNames: "NewRow0"
ProbResultsType: "Real"
problemsList.value(selProblem):
ProbResultsNames: non-existent
ProbResultsType: non-existent
EDIT 2:
class ProblemSets
{
public:
ProblemSets();
virtual ~ProblemSets();
ProblemSets(const ProblemSets& other);
ProblemSets& operator=(const ProblemSets& other);
//I hid getters and setters to avoid pollution on the post
private:
int index;
bool usingBenchmark;
QString functionSelected;
QString info;
QMap<int, QString> probVars_name, probVars_type, probResultsNames, probResultsTypes;
QMap<int, float> probVars_min, probVars_max;
QMap<int, int> probVars_stpSize, probVars_stp;
int varsNumber; // holds how many vars has been created, just for display purposes
int resNumber; // holds how many results has been created, just for display purposes
};
A simple test proves that QMap works as expected:
QMap<int, QString> mm;
mm.insert(1, "Test1");
qDebug() << mm[1]; // "Test1"
mm.remove(1);
qDebug() << mm[1]; // "" (default constructed value)
mm.insert(1, "Test2");
qDebug() << mm[1]; // "Test2"
Which means that the problem lies in your code.
This statement itself is highly suspicious:
That last line appears to be doing nothing!
Because then you go on to say that the map still contains the "old value". But you removed that key, so if the insert() method didn't work, you shouldn't be getting the old value, but a default constructed value.
Which means that the problem is most likely that nProblem has the same value as the one that is previously associated to that key in the map. The map works, you values are likely wrong.
Found the issue! I didn't have both the variables declared on the copy method of the ProblemSets class.
Solved simply adding them to the copy method
MainWindow::ProblemSets::ProblemSets(const ProblemSets& other)
{
// copy
index = other.index;
usingBenchmark = other.usingBenchmark;
functionSelected = other.functionSelected;
info = other.info;
probVars_name = other.probVars_name;
probVars_type = other.probVars_type;
probVars_min = other.probVars_min;
probVars_max = other.probVars_max;
probVars_stpSize = other.probVars_stpSize;
probVars_stp = other.probVars_stp;
//here
probResultsNames = other.probResultsNames;
probResultsTypes = other.probResultsTypes;
//
varsNumber = other.varsNumber;
resNumber = other.resNumber;
}
I had this issue before with the std::vector class, and that's why I suspected that could be that. Thanks to everyone that helped!
I am trying to print caller function, line number and file name without throwing an error for normal debugging purpose in QML. I can print caller function name as follows
console.log("Caller Function Name"+arguments.callee.caller.name);
You can override qInstallMessageHandler default function and provide your custom function which also prints line number / caller. You can find an example in the linked documentation. Another partial example:
void loggingMessageHandler(QtMsgType type, const QMessageLogContext & context, const QString & msg)
{
QString timeStr(QDateTime::currentDateTime().toString("dd-MM-yy HH:mm:ss:zzz"));
QString contextString(QString("[%1 %2]").arg(context.file).arg(context.line));
mutex.lock();
QString level;
if(logFile.isOpen())
{
switch (type) {
case QtInfoMsg: level = QString("INF"); break;
case QtDebugMsg: level = QString("DEB"); break;
case QtWarningMsg: level = QString("WAR"); break;
case QtCriticalMsg: level = QString("CRT"); break;
case QtFatalMsg: level = QString("FTL"); break;
}
QTextStream stream(&logFile);
stream << timeStr << " " << contextString << "\t" << level << "\t" << msg << endl;
stream.flush();
}
#if defined(Q_OS_WIN)
OutputDebugString(reinterpret_cast<const wchar_t *>(level.append(' ' + msg + '\n').utf16()));
#elif defined(Q_OS_ANDROID)
android_default_message_handler(type, context, level.append(" " + msg));
#else // MACX || IOS || LINUX
fprintf(stderr, "%s\n", level.append(" " + msg).toLocal8Bit().constData());
#endif
mutex.unlock();
}
If logFile is open, logging data is wrote to that in a critical section delimited by a QMutex otherwise it is simply output to the standard output of each platform.
Whatever is the handler you define, it can be combined with categorized logging (available since Qt 5.2) to easily setup a custom logging facility tailored on your needs. You just need to define your logging categories, as described in this blog post, and call qCDebug, qCInfo(), qCWarning() and so on. Depending on the active categories (set via the static function setFilterRules() of QLoggingCategory) different logging info can be printed or skipped.
That's especially interesting now that Qt 5.8 is available. Since this release, you can use categories also in QML, i.e. you can call console functions and pass along a category, e.g.
function myFancyFunction() {
// foo code
console.log(myFancyCategory, "message");
// bar code
}
Also, categories declaration can be done fully in QML via the ad hoc type LoggingCategory.
ADDENDUM (Qt < 5.0)
The proposed solution works in a Qt 5.0+ environment with categories fully usable with Qt 5.3+ and QML categories available in Qt 5.8+; in a Qt 4.x environment you should override qInstallMsgHandler but you do not have a QMessageLogContext. That means you should manage file/line info outside the handler, e.g. you have to use Q_FUNC_INFO or rely on __FILE__ and __LINE__ in C++ (note that the latters have been removed in latest 5.x releases as e.g. discussed here).
I am trying to compile my first VexCL program using the thrust example and I get the following error message:
raw_ptr is not a member of 'vex::backend::opencl::device_vector'
Here is the code
vex::Context ctx(vex::Filter::Env && vex::Filter::Count(1));
std::cout << ctx << std::endl;
vex::profiler<> prof(ctx);
typedef int T;
const size_t n = 16 * 1024 * 1024;
vex::vector<T> x(ctx, n);
vex::Random<T> rnd;
// Get raw pointers to the device memory.
T *x_begin = x(0).raw_ptr(); // Here is where the error is occurring.
T *x_end = x_begin + x.size();
I do not understand the language well enough. I appreciate any help in this matter.
Thanks
Chris
The thrust example is not the best to start with, as it deals with interfacing VexCL and Thrust (another high-level library that is targeted on CUDA).
So in order to compile the example, you need to use the CUDA backend in VexCL. That is, you need to define VEXCL_BACKEND_CUDA preprocessor macro
and to link against libcuda.so (or cuda.lib if on Windows) instead of libOpenCL.so/OpenCL.lib.
The error you got is because the device_vector class only exposes raw_ptr() method when on CUDA backend.
I am trying to get networking information (IP Address, Netmask, Route etc.) for all my interfaces in Qt using NetworkManager DBus interface. The problem is when I try to access the property "Addresses" of org.freedesktop.NetworkManager.IP4Config I get the following error
QDBusAbstractInterface: type QDBusRawType<0x616175>* must be registered with QtDBus before it can be used to read property org.freedesktop.NetworkManager.IP4Config.Addresses
Addresses are invalid
Error 2 = "Unregistered type QDBusRawType<0x616175>* cannot be handled"
However I can get the value of this property using dbus-send with following command.
dbus-send --system --print-reply --dest=org.freedesktop.NetworkManager \
/org/freedesktop/NetworkManager/IP4Config/0 \
org.freedesktop.DBus.Properties.Get \
string:"org.freedesktop.NetworkManager.IP4Config" \
string:"Addresses"
I can also get good values for above interface's mentioned property via qtdbusviewer. Following is my code snippet.
QDBusInterface interface(NM_DBUS_SERVICE, NM_DBUS_PATH, NM_DBUS_IFACE, QDBusConnection::systemBus());
// Get a list of all devices
QDBusReply<QList<QDBusObjectPath> > result = interface.call("GetDevices");
foreach (const QDBusObjectPath& connection, result.value()) {
QDBusInterface device(NM_DBUS_SERVICE, connection.path(), "org.freedesktop.NetworkManager.Device", QDBusConnection::systemBus());
if ( device.property("DeviceType").toInt() == NM_DEVICE_TYPE_ETHERNET ) {
// Get the IPv4 information if the device is active
if ( device.property("State").toInt() == NETWORK_DEVICE_CONNECTED ) {
QVariant ipv4config = device.property("Ip4Config");
if ( ipv4config.isValid() ) {
QDBusObjectPath path = qvariant_cast<QDBusObjectPath>(ipv4config);
QDBusInterface ifc(NM_DBUS_SERVICE, path.path(), "org.freedesktop.NetworkManager.IP4Config", QDBusConnection::systemBus());
if ( ifc.isValid() ) {
qDebug() << "Error 1 = " << ifc.lastError().message(); // No error. Everything is OK.
QVariant addresses = ifc.property("Addresses"); // Throwing the QDBusAbstractInterface Error where the property is good and does exist.
if ( addresses.isValid() ) {
qDebug () << "Addresses are valid";
} else {
qDebug () << "Addresses are invalid";
}
qDebug() << "Error 2 = " << ifc.lastError().message();
}
}
}
}
}
UPDATE # 1
I think it appears to be problem of types. Qt-Dbus type system does not understand the type of "Addresses" property so unable to create a QVariant out of it. So I added following lines before reading the property "Addresses". NetworkManager defines the property Addresses as following type, so I guess my typedef is good.
aau - "Array of tuples of IPv4 address/prefix/gateway. All 3 elements of each tuple are in network byte order. Essentially: [(addr, prefix, gateway), (addr, prefix, gateway), ...]"
typedef QList<QList<uint> > Addresses;
Q_DECLARE_METATYPE(Addresses)
qDBusRegisterMetaType<Addresses>()
QVariant addresses = ifc.property("Addresses");
Also I switched to Qt 5.1 (Earlier I was using 4.8), and I am getting the same error in following form.
Cannot construct placeholder type QDBusRawType
Thoughts / Suggestions
Regards,
Farrukh Arshad.
So far as per my research the problem is related to the type conversion. The property value is in the form of aau (as per NM Dbus documentation). QDbusInterface.property returns QVariant. It does find the property but unable to determine the type of the property hence giving me the error message. But my concern is, I have registered the custom type of this property with the Qt Meta Object system as I have mentioned in the Update # 1 then why it is giving me this error my type was registered with the system properly and qDBusRegisterMetaType did returned me a valid integer. In Qt 5.1 the origin of the error is in qdbusmaster.cpp. One article suggests to register meta type as mentioned below, but to no avail.
qRegisterMetaType<Addresses>("Addresses");
qDBusRegisterMetaType<Addresses>();
For now I don't have time to further dig into to see if it is some bug or I am missing something, but I will update this post once I have actual solution.
WORKAROUND
Following workaround will work to read the given property value. For this workaround to work you need to add qdbus-private instead of qdbus and include .
QVariant ipv4config = device.property("Ip4Config");
if ( ipv4config.isValid() ) {
QDBusObjectPath path = qvariant_cast<QDBusObjectPath>(ipv4config);
QDBusMessage message = QDBusMessage::createMethodCall(NM_DBUS_SERVICE, path.path(), QLatin1String("org.freedesktop.DBus.Properties"), QLatin1String("Get"));
QList<QVariant> arguments;
arguments << "org.freedesktop.NetworkManager.IP4Config" << "Addresses";
message.setArguments(arguments);
QDBusConnection connection = QDBusConnection::systemBus();
QDBusMessage reply = connection.call(message);
foreach(QVariant var, reply.arguments()) {
qDebug () << "String = " << QDBusUtil::argumentToString(var).toHtmlEscaped();
}
}
The string will show you the IP Address / Subnet Mask / Router IP which you will have to extract from the output. For record, I have taken this approach from qdbusviewer.
This is not the the right solution, but it will get you out of trouble for the time being. There is also a good article suggesting usage of custom types with Qt Dbus.
http://techbase.kde.org/Development/Tutorials/D-Bus/CustomTypes
The best solution I've found for this has been to write a QDBusAbstractInterface implementation:
typedef QList<QList<uint> > UIntListList;
Q_DECLARE_METATYPE(UIntListList)
class DBusIP4ConfigInterface : public QDBusAbstractInterface
{
Q_OBJECT
public:
DBusIP4ConfigInterface(const QString &service, const QString &path, const QDBusConnection &connection,
QObject *parent = 0)
{
qDBusRegisterMetaType<UIntListList>();
}
virtual ~DBusIP4ConfigInterface() { }
Q_PROPERTY(UIntListList Addresses READ addresses)
UIntListList addresses() const
{
return qvariant_cast<UIntListList>(property("Addresses"));
}
Q_PROPERTY(QString Gateway READ gateway)
QString gateway() const
{
return qvariant_cast<QString>(property("Gateway"));
}
Q_SIGNALS:
void PropertiesChanged(const QVariantMap &properties);
};
This has the added advantage of being pretty easy to use:
UIntListList addresses = m_dbusIP4Config->addresses();
Q_ASSERT(addresses.size() >= 1);
Q_ASSERT(addresses[0].size() == 3);
QHostAddress ip = QHostAddress(qFromBigEndian(addresses[0][0]));