For school I have to create a calendar program for the PC with Qt,
this calendar also has to give notifications a certain time before some scheduled appointment starts.
But i have trouble finding out how I exactly can create this notifications without using a while loop (which will stop my program), I would be really thankfully if someone can help me a bit with that certain part of my project.
Thank you,
Dennis
You can create a QTimer instance with interval set to 1 second. Then connect to QTimer::timeout() signal and in the slot you can check whether there is any appointment approaching, something like that:
void YourClass::slotNameForTimeoutSignal()
{
static const int fifteenMinutes = 15 * 60;
foreach (const Appointment& app : allAppoitments)
{
if ((app.getStartUnixTime() - QDateTime::currentDateTime().toTime_t()) <= fifteenMinutes)
{
notifyAboutTheAppointment(app); // implement this method to display notification
}
}
}
This code assumes you have some kind of Appointment class/structure which holds unixtime when the appoitment starts. The timer setup is easy. Somewhere in your application initialization create a timer (which should be a member field in your class), set it up and run:
YourClass::YourClass()
{
timer = new QTimer(this);
connect(timer, SIGNAL(timeout()), this, SLOT(slotNameForTimeoutSignal()));
timer->setInterval(1000);
timer->setSingheShot(false);
timer->start();
}
If you didn't know it yet, the unixtime is a time format, which is a integer number - a number of seconds that passed since the begining of 1970. Here's more details: http://en.wikipedia.org/wiki/Unix_time
Also if you're not familar with signals/slots in Qt, you should really read first about those in Qt documentation.
You can subclass QCalendarWidget to create your GUI i.e. the user can select the date when he wants the appointment. Use the QTimer to trigger the SIGNAL at your precise appointment time.
Now you can get the current date and time using QDateTime.
1. Check if the appointment is on the same date as current.
2. If yes jump to step no 4.
3. Set a timer using QTimer to emit a SIGNAL after 24 hours and connect this SIGNAL to your custom SLOT which will check if the current date is same as appointment date. Continue this step until your current date is same as appointment date.
4. Calculate the time difference between your appointment and current time and set this difference to a QTimer which will emit a SIGNAL at the required time.
5. This emitted SIGNAL would be connected a SLOT in which you are doing whatever is needed when the appointment is reached
I hope this helps you get in track.
Giving code would be like solving your homework which I don't want to do.
Related
I am writing an application to request a web page at equal intervals in order to get any changes in it (to check whether new data is received). here how i did it.
private:
QNetworkReply *r;
QNetworkAccessManager *m;
QNetworkRequest request;
QTimer *timer;
in the constructor ,
m = new QNetworkAccessManager(this);
timer = new QTimer(this);
connect(r , SIGNAL(readyRead()), this , SLOT(readit()));
connect(timer, SIGNAL(timeout()), this, SLOT(update()));
timer->start(1000);
readit function,
void MainWindow::readit(){
QString st;
st=r->readAll();
m->deleteResource(request);
ui->textBrowser->append(st);
}
update function,
void MainWindow::update()
{
request.setUrl(QUrl("http://localhost/test/default.php"));
r = m->get(request);
}
my problem is m->get(request) gets the request at its first call only, when it is called again it does nothing. I did several experiments but end up with no success results. i changed the second request to another web page using a button click but it did nothing too.
So I need help from an expert how to update the get request and get new reply multiple times.
and also i want to know am i doing a correct thing or is there mo reliable methods to get data on data change from the server than checking for the website at regular intervals.
I see following problems:
readyRead fires an arbitrary number of times per request - including zero times (!), but you treat it as if it fired exactly once. Use the finished signal, which is does what you want: fires once, no more, no less.
The update slot doesn't connect any slots to the request.
I created a class called aTimer which inherits from QTimer. I want to be able to store the time elapsed into a variable called TimeElapsed of type int. I then want to have the timer automatically started when the main window opens and for it to display the time elapsed therein.
I think I'm using the wrong timer, and I am quite confused as to which tools to be using within Qt because there are different ways of handling time. Suffice it to say that I want a stop-watch kind of module that allows me to start and stop time manually without a cap (or an interval with the case of Timer). How shall I proceed? So far, attempts to use QTimer are fruitless.
You do not really need a derived class for this task. I'd probably use a QTimer and a QElapsedTimer.
Create them in your main window constructor and set the QTimers interval according to how often the time should be updated. Also connect its timeout() signal to a function updating the displayed value. In this function you can get the elapsed time from the QElapsedTimer and update the display.
// *.h
QTimer* timer;
QElapsedTimer *eltimer;
// *.cpp
constructor(){
this->timer = new QTimer(this);
this->timer->setInterval(1000);
connect(this->timer, SIGNAL(timeout()), this, SLOT(update_ui()));
this->timer->start();
this->eltimer = new QElapsedTimer(this);
this->eltimer->start();
}
SLOT update_ui(){
qint64 msecs_elapsed = this->eltimer->elapsed();
// Insert value into ui object
}
Of course you can create some buttons to start() and stop() the QTimer
I need to check system time and if the time is right (i think the right time has passed during some interval ago would be more correct) make certain actions using wxwidgets.
I haven't found a specific class or event that can handle such conditions (I know there is wxTimer widget but it is timer - it counts time since some moment but not checks it)
Is there a better way than having a thread that just runs a while(true) loop checking system time?
Looks like the wxTimer class generates an event when the duration has elapsed:
wxTimerEvent documentation.
I would use the boost::asio deadline timer for this.
void handler(boost::system::error_code ec) { ... }
...
io_service i;
...
deadline_timer t(i);
t.expires_from_now(boost::posix_time::seconds(400));
t.async_wait(handler);
...
i.run();
http://www.boost.org/doc/libs/1_55_0/doc/html/boost_asio/overview/timers.html
You can use wxTimer to perform an action at some point in the future, just start it with the interval equal to the difference between this point and now (wxDateTime can help you with that).
I have a custom widget which displays many items in rows:
void update(){ //this is a SLOT which is connected to a button click
QVBoxLayout *layout = this->layout();
if (layout == NULL){
layout = new QVBoxLayout;
this->setLayout(layout);
} else {
QLayout_clear(layout); //this is a function that I wrote that deletes all of the items from a layout
}
ArrayList *results = generateData(); //this generates the data that I load from
for (int i = 0; i < results->count; i++){
layout->addWidget(new subWidget(results->array[i]));
}
}
The problem is that there are about 900 items and a profile reveals that simply adding the child object to the layout takes 50% of the time (constructing takes the other 50%). Overall it takes about 3 seconds to load all of the items.
When I click on the button to load more data, the entire UI freezes for the 3 seconds and then all of the items appear together when everything is done. Is there a way to progressively load more items as they are being created?
The first trick is, as Pavel Zdenek said, to process only some of the results. You want to process as many together so that the overhead (of what we're going to do in the next step) is low, but you don't want to do anything that would make the system seem unresponsive. Based on extensive research, Jakob Nielsen says that "0.1 seconds is about the limit for having the user feel that the system is reacting instantaneously", so as a rough estimate you should cut your work into roughly 0.05 second chunks (leaving another 0.05 seconds for the system to actually react to the user's interactions).
The second trick is to use a QTimer with a timeout of 0. As the QTimer documentation says:
As a special case, a QTimer with a timeout of 0 will time out as soon
as all the events in the window system's event queue have been
processed. This can be used to do heavy work while providing a snappy
user interface.
So that means that a timer with a timeout of 0 will be executed next, unless there is something else in the event queue (for instance, a mouse click). Here's the code:
void update() {
i = 0; // warning, this is causes a bug, see below
updateChunk();
}
void updateChunk() {
const int CHUNK_THRESHOLD = /* the number of things you can do before the user notices that you're doing something */;
for (; i < results->count() && i < CHUNK_THRESHOLD; i++) {
// add widget
}
// If there's more work to do, put it in the event queue.
if (i < results->count()) {
// This isn't true recursion, because this method will return before
// it is called again.
QTimer::singleShot(0, this, SLOT(updateChunk()));
}
}
Finally, test this a little bit because there's a gotcha: now the user can interact with the system in the "middle" of your loop. For instance, the user can click the update button while you're still processing results (which in the above example means that you would reset the index to 0 and reprocess the first elements of the array). So a more robust solution would be to use a list instead of an array and pop each element off the front of the list as you process it. Then whatever adds results would just append to the list.
#Adri is generally right, the twist is that the "another thread" must be the UI thread again. The point is to allow UI thread's event loop to keep spinning. The fast and dirty way is to put QCoreApplication::processEvents() in your for() cycle. Dirty because, as the doc says, it should be called "ocassionally". It might have some overhead even if there are no UI events, and you are messing Qt's performance optimization as to when and how often spin the loop. Slightly less dirty would be to call it only ocassionally, after chunks of result.
Cleaner and proper way is to create a private slot, which pops one result element (or chunk, to speed up), adds to the layout and increments index. Then it will recall itself until end of results. The gotcha is to define connect() with forced connection type Qt::QueuedConnection, so it will get deferred after already queued UI events (if any).
And because you run in only one thread, you don't need any locking over results.
Adding example per OP's request:
While #TomPanning solution is correct, it kind of hides the real solution behind QTimer which you don't need - you don't need any timing, you just need a specific non-timer behavior upon specific parameter value. This solution does the same thing, minus the QTimer layer. On the other hand, #TomPanning has a very good point about the plain ArrayList not being very good data storage, when interaction can happen in between.
something.h
signals: void subWidgetAdded();
private slots: void addNextWidget();
ArrayList* m_results;
int m_indexPriv;
something.cpp
connect(this,SIGNAL(subWidgetAdded()),
this,SLOT(addNextWidget(),
Qt::QueuedConnection);
void addWidget() {
// additional chunking logic here as you need
layout->addWidget(new subWidget(results->array[m_indexPriv++]));
if( m_indexPriv < results->count() ) {
emit subWidgetAdded(); // NOT a recursion :-)
}
}
void update() {
// ...
m_results = generateData();
m_indexPriv = 0;
addNextWidget(); // slots are normal instance methods, call for the first time
}
I need to block signals that I emit (indirectly) myself.
In C one could use g_signal_handlers_block_by_func() and the sister function unblock.
What can I use in C++ gtkmm?
I have a gtkmm dlna player, that emits the changed signal to a Gtk::HScale Widet each second, because it gets (from the outside) a signal that the song that just plays. And then I seek to the position that just where current, which set the song back a split second...
I would like to block my on changes from the seek, because I saw that a C program did that with g_signal_handlers_block_by_func.
since ptomato asked:
I never realized, that the connect method has a valuable return value:
so if you connect the signals like this:
mywidget_connection = mywidget.signal_value_changed().connect(sigc::mem_fun(*this, &MyClass::on_value_changed ));
In my situation I have 2 ways to change the value:
1.) someone pulls a slider: should update the value and seek
2.) the timer comes along and tells the new position: should update the value but not seek.
then you can block/unblock like this:
mywidget_connection.block();
mywidget.set_value(new_value);
mywidget_connection.unblock();
and this does not emit the changed signal.