C++ QT6 Получение переменной из обьекта кастомного класса в dropEvent

Рейтинг: 1Ответов: 1Опубликовано: 17.07.2025

Имеется столбец кнопок в QGridlayout row n, column 0. Кнопки - обьекты кастомного класса ButtonDrag, наследника QPushbutton. В классе есть некая переменная int row, в которую сохраняется значение номера строки из QGridLayout. Надо переопределить dropEvent окна так, чтобы при срабатывании считывалась значение переменной row из ButtonDrag для дальнейшего использования (в качестве индекса в векторе)

Есть вот такой код на питоне. Он прекрасно работает:

def dropEvent(self, e):
    pos = e.position()
    target = e.source()

    for d in range(len(self.cat_btn_ls)): # Список всех кнопок созданных в цикле.
        if pos.y() in range(self.cat_btn_ls[d].y(),
                            self.cat_btn_ls[d].y() + 30): # Высота кнопки 30px
            targ_str = self.file.categories[target.row] # Список порядок которого надо изменить в соответствии с новым порядком кнопок после перетаскивания
            self.file.categories.pop(target.row)
            self.file.categories.insert(d, targ_str)
            break

    self.write_categories()
    self.reload_categories()
    e.accept()

Потому как питону не надо указывать к какому классу будет принадлежать обьект захваченный ивентом... Как сделать тоже самое на плюсах?

void BoxCategories::dropEvent(QDropEvent *e){
    auto pos = e->position();
    auto target = e->source();

    for (auto d=0; d<cat_btn_ls.size(); d++){
        if (cat_btn_ls[d]->y() < pos.y() < cat_btn_ls[d]->y() - 30){
            auto targ_str = file.categories[target->row];
            file.categories.erase(std::next(file.categories.begin(), target->row));
            break;
        }
    }
    write_categories();
    reload_categories();
    e->accept();
}

По очевидным причинам тут это не работает, т.к e->source() это QObject у которого нет переменной row... (Да, если на питоне теперь захватить обьект в котором нет этой переменной то будет краш) Но уменя нет в этом окне других обьектов, к тому же можно сделать if else на наличие переменной)

Ответы

▲ 3Принят

Питон вроде как использует метаданные объекта. Что придется явно использовать в С++. Каждый QObject сдержит в себе QMetaObject, который хранит информацию о классе и имени объекта.

Кроме того, если заранее известен тип объекта и ваш проект поддерживает RTTI, можно обойтись банальным кастом dynamic_cast. В Qt предусмотрена функция qobject_cast не зависящая от RTTI:

auto *button = qobject_cast<ButtonDrag*>(e->source()); // вернет nullptr если тип не совпадает
if(button)  { 
    //  свершить деяние
}

qobject_cast также возвращает nullptr если класс был описан без публичного мета-интерфейса ( без макроса Q_OBJECT), что исключает возможную проблему в том случае если такой случайно или намеренно был опущен, а мы использовали (dynamic\static)_cast.

Если "деяние" - вызов слота в классе ButtonDrag, можно обойтись и без каста, а использовать QMetaMethod::invoke, вопрос в производительности. Но тогда тип вообще не важен, будет работать для всех типов с одноимённым и однотипным слотом.