How to set auto=repeat on a qaction in a qtoolbar? - c++

I'd like to use the autorepeat feature of the QToolButton class.
The problem is that the instances are created automatically when using QToolBar::addAction() and I can't find a way to reach them: QToolBar::widgetForAction() doesn't seem to work in that case (always returns NULL).
Any ideas?
Thanks

There seem to be no simple way. The best I found is to use QObject::findChldren :
foreach(QToolButton* pButton, pToolBar->findChildren<QToolButton*>()) {
if (pButton->defaultAction() == pTheActionIWant) {
...
}
}

In fact, in my case doesn't return NULL, maybe you are doing something different. My code is as follows:
QToolButton* button = dynamic_cast<QToolButton*>(
ui.toolBar->widgetForAction(ui.action));
For me it works as intended.... Maybe you aren't casting? This method returns a QWidget* and my compiler issues and error if I don't cast.
FYI, I'm using Visual Studio 2005 with Qt 4.6.

Related

Qt startDetached fails under Qt 5.15.2

I'm updating some old Qt 5.6 code to Qt 5.15.2
The Qt C++ code below opens a dos prompt, the runs a bat file, staying open when done.
cstring = "cmd /k " +QDir::currentPath()+"/cpath.bat";
QProcess::startDetached(cstring);
This code works fine under 5.6, does nothing under 5.15.2
How do I fix this for Qt 5.15.2?
You need to split the command to program and arguments. See https://doc.qt.io/qt-5/qprocess.html#startDetached-1
In your case it should be
QProcess::startDetached("cmd", {"/k", QDir::currentPath() + "/cpath.bat"});
The advantage is that now you do not need to worry for example about enclosing paths containing spaces in quotes. Consider if your current path would be "C:\my path". Then your version from Qt 5.6 would not work. While the version I presented in this answer will work out of the box. I guess it was exactly this reason that the old overload was prone to this kind of bugs that Qt decided to remove it and use only the new overload.
Ok, with my previous answer I though that the problem was with the way you are passing the arguments. But as it seems the problem is with showing the terminal... Since I am doing the same in one of my projects (HiFile file manager), I had a look how I am doing it. So here it is.
class DetachableProcess : public QProcess
{
public:
explicit DetachableProcess(QObject *parent = nullptr) : QProcess(parent)
{
}
bool detach()
{
if (!waitForStarted())
{
return false;
}
setProcessState(QProcess::NotRunning);
return true;
}
};
And then use it like this:
DetachableProcess process;
process.setCreateProcessArgumentsModifier( // this probably did the trick you need
[](QProcess::CreateProcessArguments *args)
{
args->flags |= CREATE_NEW_CONSOLE;
args->startupInfo->dwFlags &=~ STARTF_USESTDHANDLES;
});
process.start("cmd", {"/k", QDir::currentPath() + "/cpath.bat"}); // here are your params...
process.detach();
I am afraid I cannot give more explanation why this complicated method works, I do not know it. And I do not know why it was changed in Qt.
I hope it will work for you. It works for me in Qt 6.2.4, which I am currently using.

Disable QTRadioButton click [duplicate]

Any good way to make a checkbox readonly, but also not grayed-out (hardly visible).
I have used setEnabled(bool) which works, but the checkbox then is grayed-out and hardly readable
I can react on a toggle signal and reset the state. But I would need a kind of flag to determine if the box is read-only and then reset the check state, means I need to create my own CheckBox class.
setCheckable does not work either, it does not allow me to set a checked state at all:
cb = this->ui->cb_RealWorld->isCheckable();
this->ui->cb_RealWorld->setCheckable(true);
this->ui->cb_RealWorld->setChecked(someValue);
this->ui->cb_RealWorld->setCheckable(cb);
So the best thing I have is to use enable/disable and accept the grayed out style.
------- Edit -------
Following the stylesheet examples I was hoping I could set the style of a disabled checkbox like the one of an enabled. Failed so far to do so. More specific: Changing the icon like in the examples does not work for me, maybe because I am using Windows and the icons are not available under the path as in the examples.
PS: Related, but no answer here
Disabling a QCheckbox in a tricky way
Qt - How to disable QCheckBox while retaining checked state?
Following the below my code:
this->ui->cb_RealWorld->setAttribute(Qt::WA_TransparentForMouseEvents);
this->ui->cb_RealWorld->setFocusPolicy(Qt::NoFocus);
This is Devopia's solution as a function:
void SetReadOnly(QCheckBox* checkBox, bool readOnly)
{
checkBox->setAttribute(Qt::WA_TransparentForMouseEvents, readOnly);
checkBox->setFocusPolicy(readOnly ? Qt::NoFocus : Qt::StrongFocus);
}
On Windows, remember to #include "windows.h" and set flags as follows:
this->ui->cb_RealWorld->setWindowFlags(this->ui->cb_RealWorld->windowFlags() | Qt::WindowTransparentForInput);
Inherit from QCheckBox and override nextCheckState method https://doc.qt.io/qt-5/qcheckbox.html#nextCheckState do the trick.
void ReadOnlyCheckBox::nextCheckState()
{
}

Qt/C++ : Is "static_cast" ok for casting in this snippet of code?

I am using Qt5 on Windows 7. In my current app I have the following piece of code that changes the background color of some push-buttons:
...
for(int i = 0; i < layout()->count(); i++)
{
QPushButton * button = static_cast<QPushButton*>(layout()->itemAt(i)->widget());
button->setStyleSheet(backgroundColor);
}
Well, I have 2 questions about the above code:
Is it ok/correct to use static_cast or should I use some other type of casting?
Is it possible to use foreach instead of the for loop above?
You should use qobject_cast so you can check if the cast was successful. It returns 0 if the cast failed.
QPushButton * button = qobject_cast<QPushButton*>(layout()->itemAt(i)->widget());
if(button)
// cast ok
else
// cast failed
You can't use foreach as you would need a container for that.
It is technically acceptable to use static_cast only if you're sure that the layout only contains widget items and they all contain a QPushButton. Since this is error prone in face of code modifications, I don't suggest doing it.
Instead, it is desirable to use range-for in C++11 or foreach/Q_FOREACH by using a layout iterator adapter. The iterator adapter also solves the problem of iterating only the elements of a type you desire and makes your code safe in face of modifications.
Your can then use range-for and this code is safe even if no QPushButtons are in the layout, and will cope with any kind of layout item gracefully by ignoring it as it should:
for (auto button : IterableLayoutAdapter<QPushButton>(layout()))
button->setStyleSheet(backgroundColor);
If you are sure that all widgets are QPushButtons, then yes, static_cast is the best option (most efficient)
Regarding the foreach, I'm not sure you can get the QLayoutItems as some standard container, so I'm not sure you can do it.

Connecting qml-signals to Qt

I'm trying to use a qml-grid view in my code. I'm trying to couple it with my C++ code.
I've dynamically created a list view model and passed across the qml file. It works fine.
However, I'm facing trouble when I want to connect a Qml signal to Qt/c++ code. I've handled mouseArea in my Qml-rectangle and emitting a signal from there.
I'm trying to connect to the signal as follows:
QDeclarativeView *pQMLContainer = NULL;
TempWidget *pTemp = new TempWidget();
pQMLContainer = new QDeclarativeView(pTemp);
pQMLContainer->setResizeMode(QDeclarativeView::SizeRootObjectToView);
pQMLContainer->rootContext()->setContextProperty("imgModel", createModel() );
pQMLContainer->setSource(QUrl("../Temp/qml/gridview-example.qml"));
QObject *rootObject = dynamic_cast<QObject*>pQMLContainer->rootObject();
QObject::connect(rootObject, SIGNAL(keyPressed()), pTemp, SLOT(onKeyPressed()));
When the connect statement runs, I get an error: cannot connect to "null" object.
On debugging, I found I could never get "rootObject" as a valid pointer.
Where am I going wrong?
Thanks
Can you try this ? (it is example code from Qt Docs)
QObject *item = pQMLContainer->rootObject();
QObject::connect(item, SIGNAL(keyPressed()),
pTemp, SLOT(onKeyPressed()));
The code is pretty much straight:
in .cpp file:
ui->declarativeView->setSource(QUrl("qrc:/Resources/main.qml"));
QGraphicsObject *obj = ui->declarativeView->rootObject();
connect ( obj, SIGNAL(clicked()), this, SLOT(itemClicked()));
and QML File:
import Qt 4.7
Rectangle {
width: 100
height: 100
id: rect
signal clicked
Text {
text: "Hello World"
anchors.centerIn: parent
}
MouseArea {
anchors.fill: parent
onClicked: {
rect.clicked();
}
}
}
one more thing, check the location of your qml file, it should be accessible to the binary.
Perhaps you should use qobject_cast instead of dynamic_cast? See e.g. question
dynamic_cast returns NULL but it shouldn't
QGraphicsObject is a QObject so no cast should be required. If your compiler complains, try adding #include <QGraphicsObject>.
Just casting without the compiler knowing the classes is asking for trouble. (Especially as there is multiple inheritance involved.)
I could finally get this working. I'm not sure if this is the real solution to the problem, but finally this got it working:
I was setting the qml path as a relative path to my working folder. And yes the path was indeed correct, as I could see the qml and its contents. I just happened to change the qml path from relative to the working folder to relative to "qrc" as:
pQMLContainer->setSource(QUrl("qrc:/gridview-example.qml"));
instead of:
pQMLContainer->setSource(QUrl("../Temp/qml/gridview-example.qml"));
and it started working. I'm not sure if I had to add the qml to the qrc (I've just started using qml).
Thanks everyone for your support!
Mots

MFC: Showing / Hiding Splitter Panes

In my application I have a number of panes from m_wndspliter classes. What I want to do is at run time show and hide one of these panes. Whilst with the following code I can show and hide the view associated with the pane, I can't temporarily remove the pane itself.
CWnd * pCurView = m_wndSplitter2.GetPane(2, 0);
if( !pCurView == NULL )
{
if( fShow )
{
pCurView->ShowWindow(SW_SHOW);
RecalcLayout();
}
else
{
pCurView->ShowWindow(SW_HIDE);
RecalcLayout();
}
}
Any examples / ideas ?
You need to call CSplitterWnd::DeleteView to do this, which basically means that you have to save your CView elsewhere if you intend to restore it. Usually this is not a problem as all data should be stored in the CDocument rather than CView, but in practice this may not be the case.
The way I have handled this in the past is to have a copy constructor for my CView classes so I could easily store them in temporary variables.
Does this help?
http://www.codeguru.com/cpp/w-d/splitter/article.php/c1543
I have used something very similar myself,
Only the CExtSplitter class from the CodeProject article https://www.codeproject.com/Articles/2707/A-Static-Splitter-with-the-Ability-to-Hide-Show-Mu worked for me.
This is still VC6 code but it worked with minor adaptions.