如何在 FLTK 中对两个不同的小部件同时使用键盘箭头和鼠标单击?

Posted

技术标签:

【中文标题】如何在 FLTK 中对两个不同的小部件同时使用键盘箭头和鼠标单击?【英文标题】:How can I use both keyboard arrows and mouse clicks for two different widgets in FLTK? 【发布时间】:2016-12-06 03:13:11 【问题描述】:

我正在使用带有 C++ 的 FLTK 编写一个程序来滚动图像文件夹。我有一个带有下一个图像缩略图的下一个按钮,上一个按钮也是如此。我希望能够通过单击上一个和下一个按钮以及使用键盘上的左右箭头来浏览图像。

我成功地做到了,但不是同时做到的。当我只写这样一个回调函数时:

void buttonCallback(Fl_Widget* widget, void* viewerPtr) 
   Viewer* viewer = static_cast<Viewer*>(viewerPtr);
   viewer->navPressed(widget);

   viewer->redraw();

我可以单击相应的按钮来前进和后退,但是当我重载句柄函数来处理键盘箭头时,如下所示:

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);

我可以使用箭头,但是我不知道如何使用两个箭头并单击按钮。我尝试将 Fl_Widget *w 传递给句柄函数并备份到回调,并且我能够单击按钮,但不能再使用箭头。

这里是 Viewer.cpp 文件:

#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);

这里是 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

如果您需要更多信息来帮助我,请告诉我,并提前感谢您!

【问题讨论】:

更新:通过将句柄函数放入 NavButton.cpp 源代码中,我能够使其工作。 【参考方案1】:

这可能会达到你想要的。添加第三个例程来进行导航

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;

然后改另外两个来调用它。在你的处理程序中

int Viewer::handle(int e) 
switch(e) 
    ...
    case FL_KEYBOARD:
        return Navigate(Fl::event_key());
    case FL_RELEASE:
    ...
    
...

在导航中,

...
if (b->getLabel() == "Next Button") 
    ...
    Navigate(FL_Right);

else 
    ...
    Navigate(FL_Left);

【讨论】:

我能够通过将句柄函数放入我的 NavButton 类 .cpp 文件中来解决它。看着它,我确实认为您的解决方案可能已经奏效。感谢您的帮助!

以上是关于如何在 FLTK 中对两个不同的小部件同时使用键盘箭头和鼠标单击?的主要内容,如果未能解决你的问题,请参考以下文章

FLTK 中的居中小部件

将键盘事件注入 FLTK 时遇到问题

fltk 小部件顺序,按钮隐藏在另一个小部件下

从不同选项卡 FLTK 开始的线程中隐藏小部件

FLTK 绘图功能使用哪个原点?小部件还是窗口?

RUST + FLTK:从小部件 on_push() 函数访问另一个小部件