Creating a keypress signal from application button



  • Hello Qt devs!

    As the title refers to, I'm trying to implement an application button to have the same functionality as when I press "arrow key down" on my keyboard.

    I need to use signals and slots here right?

    I have tried with this:
    @connect(ui.buttonOne, SIGNAL( clicked() ), QApplication::instance(),
    SLOT( keyPressEvent(Qt::Key_Down) ));
    @
    I'm unsure what I need to have as receiver. - Where I currently have "QApplication::instance()".

    But perhaps I'm way off here?

    Thank you for your time!



    1. keyPressEvent isn't slot.
    2. signal with params can't connected to slot with params.
    3. and of course, you can't set constant param to slot in connect definition.

    you need write slot and send event from it
    something like:

    @connect(ui.buttonOne, SIGNAL( clicked() ), QApplication::instance(),
    SLOT( keyDownSlot()));

    ...

    void keyDownSlot()
    {
    QKeyEvent event(QEvent::KeyPress, Qt::Key_Down, Qt::NoModifier);
    QApplication::sendEvent(mainWindow, &event);
    }@



  • Thank you for your reply Vass!

    The argument "mainWindow" in your above post line 9, is the receiver - which is the widget to get the event, right?

    When I insert my widget it doesn't work.

    Any idea what to do?



  • [quote author="maxmotor" date="1316006856"]
    The argument "mainWindow" in your above post line 9, is the receiver - which is the widget to get the event, right?
    [/quote]

    Right.
    What are widget you insert?



  • Yes and no,

    just sending a keyPress event does not do the same as a real key press.
    First of all key events are sponataneous events...
    second, the release event is missing

    You can have a look at QtTest, how they do it. They have possibilities to simulate key events there.



  • @Voss
    It is a QTableWidget

    @Gerolf
    I will have a look at QtTest. Thanks.



  • I think what you really want to do is not simulate the key event, but rather connect your signal to a slot that does the same thing as the key event. QTableWidget might already have such a slot. (Unless you are looking for other side effects than just the functionality provided by the key press.)

    Edit: No, there does not seem to be such a slot, but you could create your own slot that uses the QTableView::moveCursor() function.



  • [quote author="ludde" date="1316011758"]I think what you really want to do is not simulate the key event, but rather connect your signal to a slot that does the same thing as the key event.[/quote]

    Yes, this is what I want :)

    I don't understand how the moveCursor() function can be used?

    Maybe I need to tell you that the software I'm working on will run on a piece of hardware with some hardware buttons and a touch screen. I want the user to be able to press either an assigned hardware button or simply click the GUI button on the screen - the effect should be the same. I hope I'm expressing myself clear enough! :)

    Thank you for all the inputs!



  • Did you look at the documentation of moveCursor()? You simply pass en enum value as the first argument, e.g. QAbstractItemView::MoveDown for moving down. The second argument can just be Qt::NoModifier, unless you want to also simulate the use of shift / control buttons.

    Or maybe your problem was that it is a protected method? You need to subclass QTableView and put your slot there to be able to use it.



  • I'm sorry. As you might already guessed I'm new to Qt - and I'm not really that experienced in C++ either.

    The compiler does indeed complain about it being a protected method.

    So I need to subclass QTableView into my class. Something like this?:

    [EDIT: Notice the below code is oh so very wrong. Don't use it :) But I guess you already knew ]

    @
    class QTableView : public MyClass
    {
    void QTableView::keyDownSlot(){
    ui.tableWidget->moveCursor(QAbstractionItemView::MoveDown, Qt::NoModifier);
    }
    };
    @

    And then I should be able to use the slot in MyClass? Is it something like this?

    I'm trying to make it work but I keep getting errors..



  • No offence, but it looks like you might need to learn some basic C++ to actually get that to work... :)

    Yes, what you need to do is something like the above, but not quite. You need a constructor for your class, and you need to declare your slot as a public slot. And you've got the inheritance order the wrong way around. You should be able to find out how to subclass a Qt widget class from some example. I'd say at least 50% of writing a Qt application is about subclassing existing Qt classes, so it's a good idea to learn how to do that properly.



  • Hm your right ludde. From the looks of it I do indeed need to learn some basic C++. My attempt at writing some code failed miserably. I don't know what I was thinking.

    Do I dare to try again? :)

    I will try to explain my overall structure. So please bear with me.

    I have a Parent_ui class which inherits from QWidget. This Parent_ui holds some basic setup of my windows. This is inherited in all my ui's in order to setup the same window size etc. It is in all these ui's I want to implement something to handle a press of a GUI button (Must function the same way as if I use the arrow keys on my keyboard).

    Okay, so in order to achieve my goal, I also need to inherit QTableView in my Parent_ui (Multiple inheritance)?

    I see that QTableView inherits (not all functions) from QWidget. Does this mean I can just entirely delete QWidget as my parent/base class and use the QTableView instead?

    I can't think anymore tonight. Too tired. Looking forward to your replies.

    I am very grateful for your time and patience.



  • Could this be a possible structure?

    http://imageshack.us/photo/my-images/99/possibleguiprogramstruc.png

    Or would it be possible to subclass both QWidget and QTableView in Parent_ui? I'm having a hard time figuring this out :(

    EDIT: Hm - Just tried creating a separate class for holding my slot like my diagram above shows.

    @void Test_class::keyDownSlot(QTableView widget) {
    widget.moveCursor(QAbstractItemView::MoveDown, Qt::NoModifier);

    }
    @

    I guess I'm still far away from a solution :(



  • I'm sorry, but that picture does not say much to me... Looks like you are using Qt Designer to design your widgets, which is something I have never done (and hopefully never will do :). So someone else will have to help you with that.

    Regarding multiple inheritance, you cannot inherit from two QObject subclasses, so that's not an option.

    I don't know what you are using your QWidgets for, but maybe what you want to do is something like this:

    Create a subclass of QTableView, e.g. MyTableView, which has a couple of new slots moveUp(), moveDown() etc.

    Create a subclass of QWidget, MyWidget that has a layout and contains some buttons and an instance of MyTableView.

    Connect the clicked() signals of the buttons to the corresponding signals in the MyTableView instance, e.g. in the MyWidget constructor.

    Hope this helps.



  • Thank you so much ludde!

    What you describe is almost what I sketch in my diagram. The only difference I guess is that I had all my UI's have an instance of my QTableView subclass. Of course it should be MyWidget (In my case Parent_ui) that should have the instance of the QTableView subclass.

    I will try this out!

    Thank you for your time!

    EDIT: Come to think about it, in my case the subclasses of Parent_ui needs the instance of MyTableView. This is because it is here the buttons and QTableView is created.



  • I get this error when trying to build:

    error: 'QTableView& QTableView::operator=(const QTableView&)' is private

    The header file of MyTableView looks like this:

    @#include "qtableview.h"

    class MyTableView: public QTableView {

    Q_OBJECT;

    public:
    MyTableView(QWidget* parent = 0);
    virtual ~MyTableView();
    public slots:
    void key_down();
    void key_up();

    };@

    Do I need to change something here? Or does it look right?



  • First, not related with your problem things:

    1. ';' not needed after Q_OBJECT - it's macros
    2. 'virtual' keyword for destructor not needed in your class, because it's already defined as virtual in base class.

    Second, your error:
    Can you show line where error was happen?
    For subclasses of QObject assignment operator and copy constructor always are private.



    1. Okay - I'll correct that.
    2. When I remove the virtual keyword I get a warning:

    "Class "MyTableView" has virtual method 'qt_metacall' but non-virtual destructor"

    1. I get the error in line 3 in the code showed in my previous post. I will add the code again, with the changes you mentioned.

    @#include "qtableview.h"

    class MyTableView: public QTableView {

    Q_OBJECT

    public:
    MyTableView(QWidget* parent = 0);
    ~MyTableView();
    public slots:
    void key_down();
    void key_up();

    };@

    Thank you for your time.



    1. didn't you forget implement destructor body?
    2. Ok, please, show code line where you create instance of MyTableView class or line where you use this instance as parameter of method


  • I think the build error probably has nothing to do with the definition of your MyTableView class, but rather how you use it. Maybe you are using an assignment with a MyTableView object somewhere, where you should really be assigning a pointer?



  • My setup.h file:

    @#include "ui_setup.h"
    #include "parent_ui.h"
    #include "mytableview.h"

    class Setup: public Parent_ui {
    Q_OBJECT

    public:
    Setup(QWidget *parent = 0);
    ~Setup();
    MyTableView myTableViewInstance;

    private:
    Ui::SetupClass ui;
    void createActions();

    private slots:
    void up();
    void down();
    void enter();
    void back();

    };@

    My setup.cpp file:

    @#include "setup.h"
    #include <QListWidget>

    Setup::Setup(QWidget *parent) :
    Parent_ui(parent) {

    ui.setupUi(this);
    Parent_ui::ui.headerLabel->setText("SETUP");

    myTableViewInstance = new MyTableView();
    }

    Setup::~Setup() {

    }
    @

    The error I get when calling "myTableViewInstance = new MyTableView();":

    'QWidget' is an inaccessible base of 'MyTableView'



  • It's because you are assigning a pointer to an object. myTableViewInstance has to be a pointer.



  • ludde are right:
    in your setup.h file
    @
    ...
    MyTableView *myTableViewInstance;
    ...
    @



  • That was it, thank you :)

    Okay to get back to the subject (Which I slowly turned away from introducing other challenges :) ).

    I have made a slot in MyTableView:

    @void MyTableView::key_down(){
    QTableView::moveCursor(QAbstractItemView::MoveDown, Qt::NoModifier);
    }@

    This is then used in my setup.cpp file:

    @void Setup::createActions() {

    QObject::connect(ui.buttonTwo, SIGNAL(clicked()), this, SLOT(myTableViewInstance->key_down()));

    }@

    This has no effect on my QTableWidget though. But I guess it's me and my coding which is faulty again. Can you see from my code snippets what I'm doing wrong?



  • @ connect(ui.buttonTwo, SIGNAL(clicked()), myTableViewInstance, SLOT(key_down()));
    @



  • I get this error: 'QObject' is an inaccessible base of 'MyTableView'



  • Please show MyTableView constructor implementation



  • It is empty :/

    @MyTableView::MyTableView(QWidget* parent) : QTableView(parent){

    }@



  • oh... I haven't more ideas :)

    Try change
    @#include "qtableview.h"@
    to

    @#include <QTableView>@

    if nothing changes, just put all your sources to file hosting and get me link :)



  • I have sent you a link :)



  • Oh... many points:

    1. In your sources
      @class MyTableView: private QTableView {@

    although, in example above you wrote:
    @class MyTableView: public QTableView {@

    1. You don't needed MyTableView, you already have QTabletWidget on form
    2. You don't needed inheritance in this case.
    3. In setup.cpp
      I rewrite some things:
      It's for local slot, because MyTableView not needed anymore
      @connect(ui.buttonTwo, SIGNAL(clicked()), this, SLOT(down()));@

    in slot, as example, you can add any checks and other logic to their:
    @void Setup::down() {
    Parent_ui::ui.tableWidget->selectRow(Parent_ui::ui.tableWidget->currentRow() + 1);
    }@

    same for up slot:
    @void Setup::up() {
    Parent_ui::ui.tableWidget->selectRow(Parent_ui::ui.tableWidget->currentRow() -1);

    }@



  • Vass you are very kind!

    I will have a look at this the first thing in the morning.

    Especially you and ludde have been a big help so far dealing with my lack of Qt/C++ skills.

    Thank you guys!



  • I just wanted to tell you that my code is now working as intended! - Thanks to you!

    I'm very impressed of the willingness to help out on this forum. And the fast response was superb.

    I'm almost positive that we will talk again! ;)

    Thank you so much for your time!



  • [quote author="maxmotor" date="1316166090"]I just wanted to tell you that my code is now working as intended![/quote]

    Glad to hear! :)
    However, I highly recommend you learning C++ - it just save your time in future


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.