I am using FLTK with C++ to write a program to scroll through a folder of images. I have a next button with the thumbnail for the next image, and the same for the previous button. I want to be able to go through the images by clicking the previous and next buttons as well as using the left and right arrows on the keyboard.
I succeeded in doing this, however not at the same time. When I only write a callback function like so:
void buttonCallback(Fl_Widget* widget, void* viewerPtr) {
Viewer* viewer = static_cast<Viewer*>(viewerPtr);
viewer->navPressed(widget);
viewer->redraw();
}
I can click the respective buttons to go forward and backwards, however when I overload the handle function to handle the keyboard arrows like so:
int Viewer::handle(int e) {
switch(e) {
case FL_FOCUS:
case FL_UNFOCUS:
return 1;
case FL_KEYBOARD:
if ( Fl::event_key() == FL_Left) {
prev->do_callback();
return(1);
} else if (Fl::event_key() == FL_Right) {
next->do_callback();
return(1);
}
return 1;
case FL_RELEASE:
do_callback();
return 1;
}
return Fl_Widget::handle(e);
}
I can use the arrows, however I cannot figure out how to use both arrows and clicking on the buttons. I have tried passing the Fl_Widget *w through to the handle function and back up to the callback, and I was able to click on the buttons, but could no longer use the arrows.
Here is the Viewer.cpp file:
#include <iostream>
#include "Viewer.h"
using namespace std;
void buttonCallback(Fl_Widget* widget, void* viewerPtr) {
//cout << "Callback called" << endl;
Viewer* viewer = static_cast<Viewer*>(viewerPtr);
viewer->navPressed(widget);
viewer->redraw();
}
Viewer::Viewer(string imageFolder, vector<string> imageFilenames, int width = 800, int height = 600) :
Fl_Window(width, height, "Image Viewer"), imageFolder(imageFolder), imageFilenames(imageFilenames), currentIndex(0), nextIndex(1), prevIndex(imageFilenames.size()-1),
prev(nullptr), next(nullptr), imageBox(nullptr), pic(nullptr) {
prev = new NavButton(getPathFilename(imageFilenames.at(prevIndex), true), "Previous Button", borderSize, this->h() - borderSize - thumbnailSize - borderSize, thumbnailSize, imageFilenames.size() - 1);
next = new NavButton(getPathFilename(imageFilenames.at(nextIndex), true), "Next Button",
this->w() - borderSize - thumbnailSize - borderSize, this->h() - borderSize - thumbnailSize - borderSize, thumbnailSize, imageFilenames.size()-1);
imageBox = new Fl_Box(borderSize, borderSize, this->w() - (2*borderSize), this->h() - (2*borderSize) - thumbnailSize - 2*borderSize);
//imageBox->box(FL_BORDER_BOX); // useful to see where the full size of the widget holding the images
pic = new Fl_JPEG_Image(getPathFilename(imageFilenames.at(currentIndex)).c_str());
imageBox->image(pic);
this->end();
prev->callback(buttonCallback, static_cast<void*>(this));
next->callback(buttonCallback, static_cast<void*>(this));
}
string Viewer::getPathFilename(string filename, bool thumb) {
string thumbPart = "";
if (thumb) thumbPart = "t_";
return imageFolder + "/" + thumbPart+ filename;
}
void Viewer::navPressed(Fl_Widget *widget) {
NavButton* b = dynamic_cast<NavButton*>(widget);
// adds to the click counts to keep track of them
b->addClickCount(); b->addTotalClicks();
cout << b->getLabel() << " has been pressed " << b->getClickCount() << " times." << endl;
cout << "All buttons have been pressed " << b->getTotClicks() << " times." << endl;
// determines which button is pressed
if (b->getLabel() == "Next Button") {
changeAllInds(true);
// check to see if at end of list
if ((nextIndex) > imageFilenames.size()-1) {
nextIndex = 0;
} else if (currentIndex > imageFilenames.size()-1) {
currentIndex = 0;
} else if (prevIndex > imageFilenames.size()-1) {
prevIndex = 0;
}
// changes main image
pic = new Fl_JPEG_Image(getPathFilename(imageFilenames.at(currentIndex)).c_str());
imageBox->image(pic);
// changes thumbnails
prev->setImage(getPathFilename(imageFilenames.at(prevIndex), true).c_str());
next->setImage(getPathFilename(imageFilenames.at(nextIndex), true).c_str());
} else {
changeAllInds(false);
// check to see if at end of list
if ((nextIndex) < 0) {
nextIndex = imageFilenames.size()-1;
} else if (currentIndex < 0) {
currentIndex = imageFilenames.size()-1;
} else if (prevIndex < 0) {
prevIndex = imageFilenames.size()-1;
}
// changes main image
pic = new Fl_JPEG_Image(getPathFilename(imageFilenames.at(currentIndex)).c_str());
imageBox->image(pic);
// changes thumbnails
prev->setImage(getPathFilename(imageFilenames.at(prevIndex), true).c_str());
next->setImage(getPathFilename(imageFilenames.at(nextIndex), true).c_str());
}
//cout << currentIndex << endl;
cout << endl;
}
void Viewer::changeAllInds(bool increase) {
if (increase) {
currentIndex++; nextIndex++; prevIndex++;
} else {
currentIndex--; nextIndex--; prevIndex--;
}
}
int Viewer::handle(int e) {
switch(e) {
case FL_FOCUS:
case FL_UNFOCUS:
return 1;
case FL_KEYBOARD:
if ( Fl::event_key() == FL_Left) {
prev->do_callback();
return(1);
} else if (Fl::event_key() == FL_Right) {
next->do_callback();
return(1);
}
return 1;
case FL_RELEASE:
do_callback();
return 1;
}
return Fl_Widget::handle(e);
}
And here is Viewer.h:
#ifndef VIEWER_H
#define VIEWER_H
#include <vector>
#include <string>
#include <FL/Fl_Window.H>
#include <FL/Fl_Box.H>
#include "NavButton.h"
class Viewer : public Fl_Window {
std::vector<std::string> imageFilenames;
Fl_Box *imageBox; // Holds image being shown
Fl_JPEG_Image *pic; // Image being shown
NavButton* prev; // Button to go to previous item
// Image is thumbnail of previous image
NavButton* next; // Button to go to next item
// Image is thumbnail of next image
int currentIndex; // Index of the image currently shown
int nextIndex; // Index of next image
int prevIndex; // Index of previous image
// private helper functions
std::string imageFolder;
std::string getPathFilename(std::string filename, bool thumb=false);
public:
static const int thumbnailSize = 50; // size of NavButton
static const int borderSize = 10; // size of border between window edge and widgets
void navPressed(Fl_Widget* widget);
// constructor
Viewer(std::string, std::vector<std::string>, int, int);
virtual int handle(int e);
//int key_handle(int e, int key);
//int mouse_handle(int e);
void changeAllInds(bool increase);
};
#endif
Please let me know if you need any more info to assist me, and thank you in advance!
This may achieve what you want. Add a third routine to do the navigation
int Navigate(int key)
{
if ( key == FL_Left) {
prev->do_callback();
return(1);
} else if (key == FL_Right) {
next->do_callback();
return(1);
}
return 1;
}
Then change the other two to call it. In your handler
int Viewer::handle(int e) {
switch(e) {
...
case FL_KEYBOARD:
return Navigate(Fl::event_key());
case FL_RELEASE:
...
}
...
In navpressed,
...
if (b->getLabel() == "Next Button") {
...
Navigate(FL_Right);
}
else {
...
Navigate(FL_Left);
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.