I've used Qt's MainWindow class before, and I have never had any problems.
Right now, I have a button called addLocation that is supposed to create a QInputDialog and get a string from the user, and add it to a QStringList called locationList, which is a public field of my uiactions.h file, declared like this within the header:
class UiActions{
public:
QStringList locationList;
//function prototypes
};
I have a function in my mainwindow.cpp file to handle the event of my addLocation button being clicked, defined as such:
void MainWindow::on_addLocation_clicked()
{
UiActions actions;
actions.addLocation();
}
And my addLocation function is defined as follows in my uiactions.cpp file:
void UiActions::addLocation()
{
bool j; //Input Dialog Handler
QDebug debugTxt(QtDebugMsg);
locationList << QInputDialog::getText(NULL, "Add Location",
"Location Name:", QLineEdit::Normal,
NULL, &j);
}
Whenever I click the addLocation button, the program shows an input dialog, lets me type something, and then hangs for a few seconds and crashes after clicking "ok."
I added some lines under the input dialog to see if the problem was in the QInputDialog, like this:
if(j){
debugTxt << "Input dialog success";
}
else{
debugTxt << "Input failed.";
}
And it would print out "Input dialog success" to the debug console, telling me the problem is not in my use of the QInputDialog.
When it crashes, this is all the error information I get:
The program has unexpectedly finished.
[insert path to EXE here] crashed
I believe this is all of the relevant information. What would be causing the program to crash?
EDIT: I ran with the debugger (should have done this first) and I'm getting a segmentation fault. I wonder what would be causing this, as I'm not doing any pointer trickery. I have a suspicion that it has something to do with the way I'm using QStringList locationList
The highlighted assembly is 0x64942cb6 <+0x0000> cmpl $0xbab1f00d,(%edx)
EDIT 2: I made a modification to the click event for my addLocation button, which is in my mainwindow.cpp file.
void MainWindow::on_addLocation_clicked()
{
UiActions actions;
//actions.addLocation();
actions.locationList << "Test Location" << "Other Data";
}
I get the same error when I try to add something to a QStringList field in the uiactions.h file as well. I'm almost positive I'm trying to access the data in there incorrectly now. Here's the interesting thing though. I have another button which I use to save the data in locationList to a text file, defined like this in my uiactions.cpp file:
bool UiActions::saveLocationList()
{
ofstream file;
file.open ("Location List.txt");
for(int i = 0;i < locationList.size(); i++){
file << locationList[i].toUtf8().data() << "\n";
}
file.close();
return true;
}
which works fine.
EDIT 3: I added a debug line: debugTxt << "\n" << locationList[0]; to the addLocation click event to see if the data was actually getting put into locationList, and it is. I'm completely confused now, since it seems I actually am accessing locationList correctly.
Related
I need to connect signal_response of FileChooserNative to the function, but I got an error when I try to use code from example from Programming with gtkmm 4 book.
When I try to compile this (g++, XCLT, macOS Big Sur):
void MyWindow::on_button_browse_clicked(){
auto dialog = Gtk::FileChooserNative::create("Please choose a folder", *this,
Gtk::FileChooser::Action::SELECT_FOLDER, "Choose", "Cancel");
dialog->set_transient_for(*this);
dialog->set_modal(true);
dialog->signal_response().connect(sigc::bind(sigc::mem_fun(*this,
&MyWindow::on_folder_dialog_response), dialog)); // <- error
dialog->show();}
A minimal .cpp to reproduce the problem is here (pastebin).
I get in instantiation of function template specialization... error. Full build log is here (pastebin).
My goal is to send response from file choosing dialog to the on_folder_dialog_response function and then show path to the folder in terminal.
What is the right code to connect response from file choosing dialog to the function?
You have a build error because the type of the extra argument you provide is not Gtk::FileChooserNative*, but rather Glib::RefPtr<Gtk::FileChooserNative> (this is what hides behind auto). So you should have:
void MyWindow::on_folder_dialog_response(int response_id, Glib::RefPtr<Gtk::FileChooserNative>& dialog)
instead. Note however that your dialog instance will die by the end of MyWindow::on_button_browse_clicked, and you will be left with a null reference.
Using Gtkmm 3.24 (you may have to adapt a bit for Gtkmm 4), I have written a small example for you:
#include <iostream>
#include <gtkmm.h>
class MainWindow : public Gtk::Window
{
public:
MainWindow();
private:
// Handler for when the user clicks the "Open file chooser dialog..." button
// on the main window. This:
//
// 1. Creates the file chooser.
// 2. Connects the response signal handler, to know about what the user
// will have done with the chooser.
// 3. Shows the file chooser.
//
// So when this is done the user is presented the file chooser.
void OnButtonBrowseClicked()
{
m_fileChooser = Gtk::FileChooserNative::create("Please choose a folder",
*this,
Gtk::FileChooserAction::FILE_CHOOSER_ACTION_SELECT_FOLDER,
"Choose",
"Cancel");
m_fileChooser->signal_response().connect(
[this](int p_responseID)
{
OnBrowseButtonClicked(p_responseID);
}
);
m_fileChooser->show();
} // m_fileChooser will not be destroyed here because it is a member.
// User response handler for the file chooser.
void OnBrowseButtonClicked(int p_responseID)
{
switch(p_responseID)
{
case Gtk::ResponseType::RESPONSE_ACCEPT:
{
std::cout << m_fileChooser->get_file()->get_path() << std::endl;
break;
}
case Gtk::ResponseType::RESPONSE_CANCEL:
{
std::cout << "Cancel clicked : " << p_responseID << std::endl;
break;
}
default:
{
std::cout << "Unexpected button clicked: " << p_responseID << std::endl;
break;
}
}
}
// Keeping a reference on the picker. This allows me to use it whenever I need. I can
// also reset it if I don't need it anymore.
Glib::RefPtr<Gtk::FileChooserNative> m_fileChooser;
Gtk::Button m_browseBtn;
};
MainWindow::MainWindow()
: m_browseBtn{"Open file chooser dialog..."}
{
add(m_browseBtn);
m_browseBtn.signal_clicked().connect(
[this]()
{
OnButtonBrowseClicked();
}
);
}
int main(int argc, char *argv[])
{
auto app = Gtk::Application::create(argc, argv, "org.gtkmm.examples.base");
MainWindow window;
window.show_all();
return app->run(window);
}
This basically lets the user choose a file and the path to its parent directory is printed to the console.
Notes:
I have used a reference to the file chooser instead of an argument (like you have tried). This lets me access it without having to change the callback's expected prototype. It also avoids the null reference issue.
I have avoided the old-school sigc::bind/sigc::mem_fun in favor of lambda expressions. I find it to be less obscure.
I have a simple Qt application - a window with text area (QTextEdit) in in. I print some text into that area, push the button and get the response depending on what has been typed in. Here is the slot responsible for what must be done for a certain input. Block else is doing just fine. But there is a problem with the if. I want it to close the app if the 'close it, please' it typed in. Before closing it shoud change the text in the text area. So there is a need for delay before closing. I tried to implement it with a cycle - doesn't work, it thinks hard and then closes anyway without showin the message.
If I use Sleep() it does the same - waits and closes without changing the text area. Why does it happen? The setText() command is before the Sleep() function, why isn't it implemented before sleep?
void Layout::text_slot()
{
QString s=m_texter->toPlainText();
if (s=="close it, please")
{
m_texter->setText("OK, my Lord!");
//for (int i=0;i<10000;i++)
//for (int j=0;j<10000;j++)
Sleep(1000*10);
QApplication::quit();
}
else
{
m_texter->setText("What 're you saying?");
}
}
Use QTimer::singleShot to wait
e.g.
void Layout::text_slot()
{
QString s=m_texter->toPlainText();
if (s=="close it, please")
{
m_texter->setText("OK, my Lord!");
// TODO: disable any user interaction here
// e.g. disable text input field
QTimer::singleShot(1000*10, qApp, SLOT(quit()));
}
else
{
m_texter->setText("What 're you saying?");
}
}
In a particular situation I need my command line based C++ application to launch a quick dialog using gtkmm 2.4. I could really use some direction here.
I tried launching the dialog as a standalone without initializing the top level window:
Gtk::Main kit( NULL,NULL );
Gtk::Window toplevel;
MyApp::myDialog d(toplevel);
int result = d.run();
This created my dialog but it doesn't close when the ok or cancel button is hit and none of quit/delete/hide api calls I could find could get rid of it. It only goes away when the program exits (even if it is created in a method which exits earlier). I'm guessing this is in part because it needs an active main window to handle some of its lifetime/visibility management. If I could make it respond normally to the ok/cancel buttons I would be all set!
Next I tried creating and launching the main window properly and launching the dialog from within the constructor of the main window. (It takes the Gtk::Main as an argument so I could try killing that directly.)
class cprompt : public Gtk::Window
{
public:
cprompt(Gtk::Main* prompt){
MyApp::myDialog* d = new MyApp::myDialog (*this);
std::cout << "ABOUT TO RUN DIALOG" << std::endl;
int result = d->run();
std::cout << "RAN DIALOG" << std::endl;
d->hide();
delete d;
std::cout << "CALLING QUIT" << std::endl;
this->hide();
Gtk::Main::quit();
prompt->quit();
//None of the above calls do anything. The empty 'top level' window hangs around and blocks until manually closed.
std::cout << "CALLED QUIT" << std::endl;
};
virtual ~cprompt(){};
};
Now the dialog works as expected, but the main window pops up after the dialog is closed (an empty gray square with an exit button) and I can't find a way to hide or exit it outside of clicking the exit button. All the calls I make to close it or quit the gtk loop automatically are inside the constructor so I'm guessing they aren't valid at that point. If I could make the whole operation shut down after the dialog returns in the window constructor, again I would be all set.
My next approach is going to be to use the top level window itself as the dialog, but I was hoping to avoid this because the dialog I need is already provided by another library and I'll have to re-implement the ui from scratch if I can't launch the dialog straight up.
Had the same problem with Gtk. To fix it, I neeeded to manually close the window and then do the gtk loop iterations. My code looks like this (for a filechooser_dialog) :
gint result = gtk_dialog_run(GTK_DIALOG(m_fileDialog));
if(result == GTK_RESPONSE_ACCEPT)
{
char* filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(m_fileDialog));
m_selectedFileName = std::string(filename);
g_free(filename);
}
gtk_window_close(GTK_WINDOW(m_fileDialog)); //Close the dialog manually
while (gtk_events_pending()) //until there are no more events :
gtk_main_iteration_do(false); //process the main iteration
I have a QProcess where i would like to output the response in a label. First off, here is what i have tried:
QProcess *proc = new QProcess();
proc->setProcessChannelMode(QProcess::MergedChannels);
proc->start(cmdLineRequest.toUtf8().constData()); // cmdLineRequest is omitted
if (!proc->waitForFinished()) {
qDebug() << "Make failed:" << proc->errorString();
ui->topBarcode->setText(QString(proc->errorString()));
} else {
qDebug() << "Make output:" << proc->readAll();
ui->topBarcode->setText(QString(proc->readAll()) + "asdf");
}
proc->readAll() is a QByteArray and setText accepts a QString. From what i've read, i should be able to cast the QByteArray to a QString, howver it does not work. I have also tried to convert proc->readAll() with the QString class
->setText(QString::fromUtf8(proc->readAll())) // not working
->setText(QString::fromLatin1(proc->readAll())) // not working
->setText(QString::fromLocal8Bit(proc->readAll())) // not working
... etc ...
It seems weird, since i'm adding pictures to labels in nearly the same matter using setPixmap(QPixmap::fromImage(image))
Any help appreciated, thank you.
Update:
If i add a QMessageBox before the end of the method that the above block of code belongs to, i can see the text added to the label. However when i close the QMessageBox, the text dissapears. Am i giving an address position to the label with proc->readAll() or how come this behaviour? Thank you.
The problem here is that you're calling proc->readAll twice; the first for the qDebug output and then again for the string which you set on the label.
{
qDebug() << "Make output:" << proc->readAll();
ui->topBarcode->setText(QString(proc->readAll()) + "asdf");
}
I expect that as QProcess is a QIODevice, it's returning a buffered byte array. When you read it, it removes that from the buffer.
Therefore, create a temporary string and read the buffer once, before calling qDebug and setting the string to the label: -
{
QString output = proc->readAll();
qDebug() << "Make output:" << output;
ui->topBarcode->setText(output + "asdf");
}
You should listen to readyReadStandardOutput() signal and call readAll() when you receive signal.
or you can call
bool waitForReadyRead(int msecs = 30000)
before calling readAll().
void combination::OnButton2()
{
// TODO: Add your control notification handler code here
m_progress.SetPos(0);
m_progress.SetRange(0,100);
combination a;
a.make_combinations(0);
}
void combination::make_combinations(int lo_val)
{
srand(time(0));
m_progress.StepIt();
ofstream fout("combination.txt",ios::app);
ofstream fout2("time.txt",ios::app);
for(int i=0; i<theApp.no_of_process; i++)
{
//m_progress.OffsetPos(100/4);
//m_progress.SetStep(200);
clock_t begin = clock();
arr[lo_val] = i;
if (lo_val == (theApp.no_of_tasks)-1)
{
for (int j=0; j<theApp.no_of_tasks; j++)
{
int number = arr[j];
fout << Matrix[j][number];
}
fout<<endl;
}
else
{
//Sleep(2);
//make_combinations(lo_val+1);
clock_t end = clock();
theApp.combination_time[i][0] = (diffclock(end, begin))/1000;
fout2 << theApp.combination_time[i][0] << endl;
}
}
}
there is a dialog on mfc with a button behine that button am calling a recursive function. i placed a progress bar on the same dialog that should tell me the progress of recursion. but iam gettin an error on clicking the button. debug assertion failed. your program caused an assertion failure. i dnt know what is wrong with my code. please help!!
ISSUE NO 2:
Iam making this project on MFC! it includes brute force capability. It also has file handling in it!! am stuck at another point! i have a couple of files with file writing! my project has multiple files .txt format! on the main MFC board i want to add an option for browsing those written files . they should open in the format they are written! any help how it can be done?? just like a browsing menu! help??
The assertion is probably because either the control does not exist on the dialog, or the variable m_progress has not been subclassed to the control. Make sure you have a DDX_Control entry for m_progress in your DoDataExchange function.