I have the function like this below, and global QVector<pid_t> pid; in the header file which elements are Linux process ids. But when I'm trying to push the button "priority" - programm unexpectedly finishes. Due to qDebugs I've realized that function interrupts after if statement. And I can not understand the matter of this problem. Function:
void MainWindow::on_priority_clicked()
{
int curI = ui->tableWidget->currentRow();
int prio = ui->prioritySpinBox->value();
try{
if(ui->tableWidget->item(curI,1)->text().isNull())
throw curI;
else {
setpriority(PRIO_PROCESS, pid.at(curI),prio);
QLabel *labelPrio = new QLabel(ui->tableWidget);
labelPrio->setText(QString::number(getpriority(PRIO_PROCESS, pid.at(curI))));
ui->tableWidget->setCellWidget(curI, 3, labelPrio);
}
}
catch(int x)
{
QMessageBox::warning(this, "Error", "Process " + QString::number(x+1) + " is not created");
}
}
Not sure if this is your problem, but if ui->tableWidget->item(curI,1) doesn't exist (or is null), then calling ->text() on it will cause a crash.
You might need to check if it exists first:
void MainWindow::on_priority_clicked()
{
int curI = ui->tableWidget->currentRow();
int prio = ui->prioritySpinBox->value();
try{
if(ui->tableWidget->item(curI,1) != nullptr)
....
Related
Using GTKMM, I'm extending the DrawingArea widget with the idea that an external process provides it with images. My CameraDrawingArea will then display the images at the right size using Cairo.
Each time an image arrives, I store it and I call the invalidate method, which eventually ends up in a call to on_draw, where I can resize and display the image.
My problem is the following:
The first 10 or 20 images are displayed as I expected.
After a while, the images keep coming from the provider process, I keep calling invalidate
but on_draw is not called any more.
To show it here, I've simplified the code so that there is nothing external to the class, and no link with other libraries. I've replaced the process providing the images by a method with for-loops, and the display of the image by printing a simple text in the middle of the widget area:
In the constructor I launch a new std::thread to call the doCapture method in the same instance. I also set up a font description, to use it later.
The doCapture method is a silly CPU eater, that does nothing except calling from time to time the refreshDrawing method, as long as keepCapturing is not false.
refreshDrawing invalidates the whole window's rectangle via a call to invalidate.
Gtk's magic is suppose to call on_draw and provide a Cairo context to draw whatever. In my case, for tests purposes, I draw a brownish centered integer.
The class destructor stops the thread by set keepCapturing to false, and waits for termination with a join.
#include "camera-drawing-area.hpp"
#include <iostream>
CameraDrawingArea::CameraDrawingArea():
captureThread(nullptr) {
fontDescription.set_family("Monospace");
fontDescription.set_weight(Pango::WEIGHT_BOLD);
fontDescription.set_size(30 * Pango::SCALE);
keepCapturing = true;
captureThread = new std::thread([this] {
doCapture();
});
}
void CameraDrawingArea::doCapture() {
while (keepCapturing) {
float f = 0.0;
for (int n = 0; n < 1000; n++) {
for (int m = 0; m < 1000; m++) {
for (int o = 0; o < 500; o++) {
f += 1.2;
}
}
}
std::cout << "doCapture - " << f << std::endl;
refreshDrawing();
}
}
void CameraDrawingArea::refreshDrawing() {
auto win = get_window();
if (win) {
win->invalidate(false);
std::cout << "refreshDrawing" << std::endl;
}
}
bool CameraDrawingArea::on_draw(const Cairo::RefPtr<Cairo::Context>& cr) {
std::cout << "on_draw" << std::endl;
static char buffer[50];
static int n = 0;
sprintf(buffer, "-%d-", n++);
Gtk::Allocation allocation = get_allocation();
const int width = allocation.get_width();
const int height = allocation.get_height();
auto layout = create_pango_layout(buffer);
layout->set_font_description(fontDescription);
int textWidth, textHeight;
layout->get_pixel_size(textWidth, textHeight);
cr->set_source_rgb(0.5, 0.2, 0.1);
cr->move_to((width - textWidth) / 2, (height - textHeight) / 2);
layout->show_in_cairo_context(cr);
cr->stroke();
return true;
}
CameraDrawingArea::~CameraDrawingArea() {
keepCapturing = false;
captureThread->join();
free(captureThread);
}
And this is my header file:
#ifndef CAMERA_DRAWING_AREA_HPP
#define CAMERA_DRAWING_AREA_HPP
#include <gtkmm.h>
#include <thread>
class CameraDrawingArea : public Gtk::DrawingArea {
public:
CameraDrawingArea();
virtual ~CameraDrawingArea();
protected:
bool on_draw(const Cairo::RefPtr<Cairo::Context>& cr) override;
private:
bool keepCapturing;
void doCapture();
void refreshDrawing();
std::thread* captureThread;
Pango::FontDescription fontDescription;
};
#endif
The problem manifests itself as follows:
When starting the application, it faithfully displays 1, 2, 3...
Between 5th and 20th iteration (it's random, but rarely outside these ranges), it stops refreshing.
Because of the cout, I can see that refreshDrawing is called be sure that invalidate is also called, but on_draw isn't.
Also, if I stop the application before it stops refreshing, then it ends up nicely. But, if I stop the application after it stops refreshing, then I see this message below (the ID value varies):
GLib-CRITICAL **: 10:05:04.716: Source ID 25 was not found when attempting to remove it
I'm quite sure that I do something wrong, but clueless about what. Any help would be appreciated.
I also checked the following questions, but they don't seem to be related with my case:
Draw signal doesn't get fired in GTKMM, when derived class doesn't call a superclass's constructor
You can't use GTK methods from any other thread than the one in which you started the GTK main loop. Probably the win->invalidate() call is causing things to go wrong here.
Instead, use Glib::Dispatcher to communicate with the main thread, or use gdk_threads_add_idle() for a more C-style solution.
Based on the answer form #ptomato, I've rewritten my example code. The golden rule is do not call GUI functions from another thread, but if you do, then acquire some specific GDK locks first. That's the purpose of Glib::Dispatcher :
If a Glib::Dispatcher object is constructed in the main GUI thread (which will therefore be the receiver thread), any worker thread can emit on it and have the connected slots safely execute gtkmm functions.
Based on that, I've added a new private member Glib::Dispatcher refreshDrawingDispatcher that will allow threads to safely the invalidate the windows area:
#ifndef CAMERA_DRAWING_AREA_HPP
#define CAMERA_DRAWING_AREA_HPP
#include <gtkmm.h>
#include <thread>
class CameraDrawingArea :
public Gtk::DrawingArea {
public:
CameraDrawingArea();
virtual ~CameraDrawingArea();
protected:
bool on_draw(const Cairo::RefPtr<Cairo::Context>& cr) override;
private:
bool keepCapturing;
void doCapture();
void refreshDrawing();
Glib::Dispatcher refreshDrawingDispatcher;
std::thread* captureThread;
Pango::FontDescription fontDescription;
};
#endif
Then, I've connected the dispatcher to the refreshDrawing method. I do this in the class constructor, which is called during GUI start up and therefore in the main GUI thread:
CameraDrawingArea::CameraDrawingArea():
refreshDrawingDispatcher(),
captureThread(nullptr) {
fontDescription.set_family("Monospace");
fontDescription.set_weight(Pango::WEIGHT_BOLD);
fontDescription.set_size(30 * Pango::SCALE);
keepCapturing = true;
captureThread = new std::thread([this] {
doCapture();
});
refreshDrawingDispatcher.connect(sigc::mem_fun(*this, &CameraDrawingArea::refreshDrawing));
}
Finally, the thread has to call the dispatcher:
void CameraDrawingArea::doCapture() {
while (keepCapturing) {
float f = 0.0;
for (int n = 0; n < 1000; n++) {
for (int m = 0; m < 1000; m++) {
for (int o = 0; o < 500; o++) {
f += 1.2;
}
}
}
std::cout << "doCapture - " << f << std::endl;
refreshDrawingDispatcher.emit();
}
}
And now, this works without further problems.
So I want to create the gui interface in Qt/cpp for the server which can be in many different states, and depending on its state the buttons in gui need to be set differently ex:
GUI:
button1 - unchecked and enabled to click
button2 - disabled(grayed out)
button3 - disabled
button3 - disabled
Then after click button1
GUI:
button1 - checked
button2 - enabled to click
button3 - enabled to click
button3 - enabled to click
But for example if server is in different state and you connect via gui the buttons should look like this:
GUI:
button1 - checked
button2 - enabled to click
button3 - disabled to click
button3 - disabled to click
Is there some established pattern/way of handling that intuitively? The biggest problem here is that if the server has a lot of different states that need the buttons to be set in a lot of different configurations. The only thing I can come up with is mapping the state of all buttons to the specific state but well... there's a lot of buttons and a lot of states.
You could try using flags, the idea is that when an event happens and you want the GUI to change you set a flag which in turn is recalled in a loop. Below you can see the general idea and concept.
If you change the state of the flag you will get a different output and it will loop over and over listening for events just write the GUI code for each in the different states.
#include <iostream>
using namespace std;
int getserverstatusfunction() {/*your code to check server status returns 0,1 or 2*/
return 0;
}
UI.button.click(true) { getresult = 1; }; //change the UI state when the button is clicked
int main() {
bool running;
while (running){
int getresult = getserverstatusfunction();
if (getresult == 0)
{
cout << "Draw flag one interface code\n";
}
else if (getresult == 1)
{
cout << "Draw flag two interface code\n";
}
else {
cout << "Draw flag three interface code\n";
}
system("pause");
return 0;
}
I've found the best way to do this is just to have a single slot-method (e.g. UpdateAllButtonStates() that updates all of your buttons and checkboxes, e.g.:
void MyWindow::UpdateAllButtonStates() // Qt-slot method
{
const bool shouldButton1BeEnabled = [...];
button1->setEnabled(shouldButton1BeEnabled);
const bool shouldButton2BeEnabled = [...];
button2->setEnabled(shouldButton2BeEnabled);
[... and so on for all enables and checked/unchecked states in your GUI]
}
... then anytime your program's internal state has changed in any way that might require an update to one or more buttons/checkboxes in the GUI, call this method explicitly, or set up a signal/slot connection that will call it for you.
The advantage of doing it this way is the simplicity -- with this approach, it's trivial to guarantee that your GUI widgets will be in updated to the expected state after any internal-state-change, because there is only one code-path to write and debug. The alternative (trying to come up with the correct transitional behavior for every possible state-change in your program) quickly leads to an intractable amount of complexity, and endless debugging and hair-pulling.
You might think the downside is inefficiency -- after all, we are updating all the buttons even though in any cases, only one of them may have changed -- but Qt's code is smart enough that calling setEnabled(false) on a button that is already disabled is a no-op (likewise calling setEnabled(true) on a button that is already enabled, and so on), so the heavyweight code of redrawing a widget's pixels will only be executed when the widget's state has actually changed.
The logic inside UpdateAllButtonStates() that calculates shouldButton1BeEnabled, etc, does get executed a lot, but it usually ends up being pretty trivial logic so that turns out not to be important. However, if for some reason that logic turns out to be expensive, you have the option of reducing the frequency at which UpdateAllButtonStates() gets executed, by using asynchronous execution and a boolean "dirty-bit", e.g.:
void MyWindow::ScheduleUpdateAllButtonStates() // Qt-slot method
{
if (_dirtyBit == false)
{
_dirtyBit = true;
QTimer::singleShot(0, this, SLOT(UpdateAllButtonStates()));
}
}
void MyWindow::UpdateAllButtonStates()
{
if (_dirtyBit == false) return;
_dirtyBit = false;
// Update button enables/checked states as previously, here
}
... then have all your internal-state-change code call ScheduleUpdateAllButtonStates() rather than calling UpdateAllButtonStates() directly; the advantage is that even if ScheduleUpdateAllButtonStates() gets called 500 times in a row, it will only result in UpdateAllButtonStates() getting called once, during the next iteration of Qt's event loop.
Enabling/disabling button UI logic can be very dirty and difficult to manage and trace. Also, sometimes we want to be in particular state and want to make a minor change like changing state of just one button. Here is an approach. It's generic but you will have to adrop it accordingly with your UI.
#include <iostream>
class UIState
{
protected:
bool btn1;
bool btn2;
bool btn3;
public:
UIState()
{
btn1 = false;
btn2 = false;
btn3 = false;
}
virtual void setBtn1State(bool new_state)
{
btn1 = new_state;
std::cout << btn1 << btn2 << btn3 << std::endl;
};
virtual void setBtn2State(bool new_state)
{
btn2 = new_state;
std::cout << btn1 << btn2 << btn3 << std::endl;
};
virtual void setBtn3State(bool new_state)
{
btn3 = new_state;
std::cout << btn1 << btn2 << btn3 << std::endl;
};
};
class UIStateAllEnabled : public UIState
{
public:
UIStateAllEnabled()
{
btn1 = true;
btn2 = true;
btn3 = true;
std::cout << btn1 << btn2 << btn3 << std::endl;
}
};
class UIStateAllDisabled : public UIState
{
public:
UIStateAllDisabled()
{
btn1 = false;
btn2 = false;
btn3 = false;
std::cout << btn1 << btn2 << btn3 << std::endl;
}
};
class UI
{
UIState * currentState;
public:
UI()
{
currentState = NULL;
}
~UI()
{
if (currentState != NULL)
{
delete currentState;
std::cout << "deleted current state" << std::endl;
}
}
void setState(UIState * new_state)
{
// should also check for if already current state?
UIState * prevState = currentState;
currentState = new_state;
if (prevState != NULL)
{
delete prevState;
std::cout << "deleted previous state" << std::endl;
}
}
void setBtn1State(bool new_state)
{
currentState->setBtn1State(new_state);
};
void setBtn2State(bool new_state)
{
currentState->setBtn2State(new_state);
};
void setBtn3State(bool new_state)
{
currentState->setBtn3State(new_state);
};
};
int main()
{
UI ui;
// enable all buttons
ui.setState(new UIStateAllEnabled);
// Now say you want to change state of a particular button within this state.
ui.setBtn1State(false);
ui.setBtn3State(false);
// switch to a completely new state, disable all buttons
ui.setState(new UIStateAllDisabled);
// customize within that sate
ui.setBtn3State(true);
return 0;
}
I am using QT and QCustomPlot to create a real time plotting tool, and the data of the plot is read from the Arduino UNO board. My application succeeded in plotting while the data is a total mess. Here is my code below (Some code is from QCustomPlot website):
void Dialog::realtimeDataSlot()
{
bool currentPortNameChanged = false;
QString currentPortName;
if (currentPortName != portName) {
currentPortName = portName;
currentPortNameChanged = true;
}
QString currentRequest = request;
QSerialPort serial;
if (currentPortNameChanged) {
serial.close();
serial.setPortName(currentPortName);
if (!serial.open(QIODevice::ReadOnly)) {
return;
}
}
static QTime time(QTime::currentTime());
// calculate two new data points:
double key = time.elapsed()/1000.0;
static double lastPointKey = 0;
if (key-lastPointKey > 0.002) // at most add point every 2 ms
{
// add data to lines:
if(serial.waitForReadyRead(-1)){
data = serial.readAll();
QTextStream(stdout) << "HERE:" << data.toDouble() << endl;
customPlot->graph(0)->addData(key, data.toDouble());
customPlot->graph(0)->rescaleValueAxis(); //rescale value (vertical) axis to fit the current data:
lastPointKey = key;
customPlot->xAxis->setRange(key, 8, Qt::AlignRight);
customPlot->replot();
static double lastFpsKey;
static int frameCount;
++frameCount;
if (key-lastFpsKey > 2) // average fps over 2 seconds
{
lastFpsKey = key;
frameCount = 0;
}
}
}
// calculate frames per second:
if (currentPortName != portName) {
currentPortName = portName;
currentPortNameChanged = true;
} else {
currentPortNameChanged = false;
}
}
When I Tried to print out the data I read from the serial port, I found the following:
HERE:1
HERE:15
HERE:150
HERE:149
HERE:149
HERE:149
HERE:150
HERE:150
HERE:15
HERE:150
HERE:149
HERE:49
HERE:150
HERE:150
HERE:1
HERE:150
The values around 150 are normal while the value that are 0, 1 to others are not. Also it is not print out at a stable speed. I don't know what happened to this, and thanks to whoever may help, and I would appreciate it if there is any better ways to implement this.
The problem here is that it is not guaranteed that the serial transmission is received all at once. So it is better to let the serial to be processed somewhere else, for instance:
// in the class definition
QSerialPort serialPort;
private slots:
void handleReadyRead();
private:
QByteArray serialBuffer;
volatile double lastSerialValue;
// In the initialization part (not the realtimeDataSlot function)
lastSerialValue = qQNaN();
serialPort.setPortName(currentPortName);
connect(&serialPort, &QSerialPort::readyRead, this, &Dialog::handleReadyRead, Qt::UniqueConnection);
if (!serialPort.open(QIODevice::ReadOnly)) {
return;
}
serialBuffer.clear();
// Other functions:
void Dialog::realtimeDataSlot()
{
...
if (key-lastPointKey > 0.002) // at most add point every 2 ms
{
if (!qIsNaN(lastSerialData))
{
// use lastSerialValue as the data.toDouble() you had before, then, at the end
lastSerialValue = qQNaN();
}
...
}
void Dialog::handleReadyRead()
{
serialBuffer.append(serialPort.readAll());
int serPos;
while ((serPos = serialBuffer.indexOf('\n')) >= 0)
{
bool ok;
double tempValue = QString::fromLatin1(serialBuffer.left(serPos)).toDouble(&ok);
if (ok) lastSerialValue = tempValue;
serialBuffer = serialBuffer.mid(serPos+1);
}
}
Explanation: whenever you receive something from the arduino the bytes are appended to a buffer. Then the byte array is parsed looking for a terminator, and if found the byte array is split and analysed. When the other function needs the data, it simply pulls the most recent one saved in the variable.
NOTE 1: I saw that you used a binary transmission. The problem is that you do not have any way to determine where the data begins and end in this way. For instance, if you receive 0x01 0x02 0x03 0x04 and you know that there are 3 bytes, are they 01..03 or 02..04 or 03, 04 and a missing one or...? The version I implemented requires you to send data in string format with a new-line terminator (simplest version, you just have to write Serial.println(doubleValue); in the arduino code), but if you need the binary version I can give you some hints
NOTE 2: The code I wrote is NOT thread safe. It will work only if the realtimeDataSlot and the handleReadyRead are called in the same thread. Note that if they belong to the same object and are called through signals this is guaranteed.
Now, this should work. But I highly discourage you from doing this. I don't know who needs to call the realtimeDataSlot(), but I think that the most correct version is something like this:
// in the class definition
QSerialPort serialPort;
private slots:
void handleReadyRead();
void receivedData(double val);
private:
QByteArray serialBuffer;
signals:
void newData(double data);
// In the initialization part (not the realtimeDataSlot function)
serialPort.setPortName(currentPortName);
connect(&serialPort, &QSerialPort::readyRead, this, &Dialog::handleReadyRead, Qt::UniqueConnection);
connect(this, &Dialog::newData, this, &Dialog::receivedData, Qt::UniqueConnection);
if (!serialPort.open(QIODevice::ReadOnly)) {
return;
}
serialBuffer.clear();
// Other functions:
void Dialog::receivedData(double val)
{
double key = time.elapsed()/1000.0;
static double lastPointKey = 0;
if (key-lastPointKey > 0.002) // at most add point every 2 ms
{
QTextStream(stdout) << "HERE:" << data.toDouble() << endl;
customPlot->graph(0)->addData(key, data.toDouble());
customPlot->graph(0)->rescaleValueAxis();
...
}
}
void Dialog::handleReadyRead()
{
serialBuffer.append(serialPort.readAll());
int serPos;
while ((serPos = serialBuffer.indexOf('\n')) >= 0)
{
bool ok;
double tempValue = QString::fromLatin1(serialBuffer.left(serPos)).toDouble(&ok);
if (ok) emit newData(tempValue);
serialBuffer = serialBuffer.mid(serPos+1);
}
}
So keep the graph responsive to events (received a new data) instead of to a timer.
One more thing: I removed the port change on purpose. I suggest you to handle it in another way: put a button to start and stop the serial, and when the serial port is started prevent the user from changing the port name. This way the user will explicitely need to shut it down when he needs to change the port. If you want your version, however, don't include it in your code, but make a slot on its own to call whenever you need to change the port name:
void changeSerialPortName(QString newName)
{
if (newName != serialPort.portName()) {
if (serialPort.isOpen())
serialPort.close();
serialPort.setPortName(newName);
if (!serialPort.open(QIODevice::ReadOnly)) {
return;
}
}
}
I have the following code:
tbb::concurrent_bounded_queue<Image> camera_queue_;
camera_queue_.set_capacity(1);
struct Image
{
int hour_;
int minute_;
int second_;
int msec_;
QImage image_;
Image(){hour_ = -1; minute_ = -1; second_ = -1; msec_ = -1; image_ = QImage();}
Image& operator=(Image const& copy)
{
this->hour_ = copy.hour_;
this->minute_ = copy.minute_;
this->second_ = copy.second_;
this->msec_ = copy.msec_;
this->image_ = copy.image_;
return *this;
}
};
In a Qt Thread :
ThreadA:
tbb::concurrent_bounded_queue<Image> image_queue_;
image_queue_.set_capacity(1);
Image cur_image_;
void Worker::process() {
while(1)
{
if(quit_)
break;
{
camera_queue_.pop(cur_image_);
image_queue_.push(cur_image_);
}
emit imageReady();
}
emit finished();
}
Image Worker::getCurrentImage()
{
Image tmp_image;
image_queue_.pop(tmp_image);
return tmp_image;
}
In Another Thread:
ThreadB:
Producer::Producer(){
work_ = new Worker();
work_->moveToThread(workerThread_);
QObject::connect(workerThread_, &QThread::finished, work_, &QObject::deleteLater);
QObject::connect(this, &Producer::operate, work_, &Worker::process);
QObject::connect(work_, &Worker::imageReady, this, &Producer::displayImage);
QObject::connect(this, &Producer::stopDecode, work_, &Worker::stop);
workerThread_->start();
emit operate();
}
void Producer::process() {
while(1)
{
if(quit_)
break;
{
camera_queue_.push(GetImage());
}
}
}
void Producer::displayImage()
{
Image tmp = std::move(work_->getCurrentImage());
widget_->showImage(tmp.image_);
}
However, In main thread, I have a function that enables user to click a button to get current image:
bool Producer::SaveImage()
{
Image img = std::move(work_->getCurrentImage());
std::string fileName = std::to_string(img.hour_) + "-" + std::to_string(img.minute_) + "-" + std::to_string(img.second_) + "-" + std::to_string(img.msec_/1000) + ".jpg";
std::string outFileName = folder + "/" + fileName;
return img.image_.save(QString::fromStdString(outFileName));
}
The problem is:
When user does not click the button to invoke Producer::SaveImage(), the Image Decoding and Showing runs smoothly. But when user invoke Producer::SaveImage(), the whole program will get stuck (Caton phenomenon ?). The GUI response becomes not that smooth. The more user invokes SaveImage, the slower the GUI response becomes.
Can anyone help to explain why ? Is there a way to solve that ?
Why do you want to use concurrent queue? It looks like there is a syncronization mechanism in place and you rely mostly on it instead of using concurrent_queue for synchronisation and communication as it is supposed for.
The issue is that when you set capacity = 1, both operations of concurrent_bounded_queue will block until there is enough space of items in the queue. E.g. if the queue contains an item already, the push operation will block. And since you control your threads with another notification mechanism, you might catch a deadlock.
In particular, try to swap the operations like below:
camera_queue_.pop(cur_image_);
emit imageReady();
image_queue_.push(cur_image_);
This should prepare the thread which receives images (if I understand this correctly) and it will block on its image_queue_.pop() method, then this thread will put new image and unblocks the recipient. There might be other issues similar to this, so, please rethink all of your synchronization.
I've been studying this thread
Processing 2.0 - Open file dialog
with regard to the use of selectinput().
I'm hoping to import point data to construct some 3d plots.
I can import the data and construct the plot ok but when trying to use
selectinput() to choose a file I run into trouble.
The difficulty I am having is that selectinput() appears to be incompatible with a P3D
window.
Using OS X10.10
for example This code works
void setup() {
size(400, 400,P3D); //3Dgraphics specified
background(0);
stroke(255);
frameRate(20);
}
void draw() {
noFill();
ellipse(mouseX, mouseY, 90, 90);
and this works
String [] myInputFileContents ;
String myFilePath;
void setup() {
selectInput("Select a file : ", "fileSelected");
while (myInputFileContents == null) {//wait
// println("wait"); //If there is nothing inside the curly brackets
//delay(3000); //this doesn't work
size(400, 400 );/// If P3D is added it won't work
background(0);
//smooth();
stroke(255);
frameRate(25);
}
}
void draw() {
box(mouseX, mouseY, 150);
println("Selected at this point " + myFilePath);
}
void mousePressed() {
selectInput("Select a file : ", "fileSelected");
}
void fileSelected(File selection) {
if (selection == null) {
println("no selection so far...");
}
else {
myFilePath = selection.getAbsolutePath();
myInputFileContents = loadStrings(myFilePath) ;// this moves here...
println("User selected " + myFilePath);
}
}
but if
size(400, 400);
is changed to
size(400,400,P3D);
The frame displays but it won't draw.
Could someone point me to the answer?
It seems that this problem is some kind of frame loading problem. This "hackish" approached worked for me under OS X 10.10 Yoesemite. It should also work under windows. Oh and whenever you use selectInput() please use mouseReleased so the function only gets called once :)
Setup() gets called twice for whatever reason, this is why we have the didPreSelect boolean.
You call mousePressed instead of mouseReleased
The loop already had the screen selection in it, this is why i changed the loop.
The delay also has problems, this is why i added the delay inside the while-loop.
Man that was quite the challenge, +1 for asking.
PS: I added an exit() if you press cancel the first time you open the application, which should be more convenient.
String [] myInputFileContents ;
String myFilePath;
boolean didPreSelect = false;
boolean secondPress = false;
void setup() {
if (didPreSelect == false)
{
didPreSelect = true;
selectInput("Select a file : ", "fileSelected");
}
//frame = null;
while (myInputFileContents == null || myInputFileContents.length < 2) {//wait
delay(1000);
}
//this doesn't work
size(400, 400, P3D);
background(0);
//smooth();
stroke(255);
frameRate(25);
}
void draw() {
box(mouseX, mouseY, 150);
//println("Selected at this point " + myFilePath);
}
void mouseReleased() {
if(secondPress == false) secondPress = true;
selectInput("Select a file : ", "fileSelected");
}
void fileSelected(File selection) {
if (frameCount < 50)
{
if (selection == null) {
println("no selection so far...");
if(secondPress == false) exit();
} else {
myFilePath = selection.getAbsolutePath();
myInputFileContents = loadStrings(myFilePath) ;// this moves here..
println("User selected " + myFilePath);
}
}
}