Evgenii Legotckoi
Evgenii LegotckoiҚыр. 1, 2015, 11 Т.Ж.

Qt/C++ - 014-сабақ. Qt-та виджеттерді динамикалық түрде жасау

Күрделі жобаларда бағдарлама интерфейсінде статикалық виджеттердің болуы жеткіліксіз болуы мүмкін, өйткені кіріс ақпарат секунд сайын өзгеруі мүмкін. Бұл Qt орналасуындағы түймелер сияқты виджеттерді динамикалық құру мәселесін тудырады.

Бұл сабақ **QPushButton түймелерін динамикалық түрде жасауды, осы түймелерден сигналдарды қабылдауды, содан кейін осы түймелерді Qt орналасуынан жоюды сипаттайды.

Код Qt 5.4.1 негізінде QtCreator 3.3.1-де жазылған.

Жоба құрылымы

Жоба құрылымының сипаттамасы:

  • DynamicButtons.pro - профиль;
  • mainwindow.h – қосымшаның негізгі терезесінің тақырып файлы;
  • mainwindow.cpp – терезенің бастапқы коды;
  • main.cpp – қолданба басталатын негізгі бастапқы файл;
  • mainwindow.ui – қосымшаның негізгі терезесінің формасы;
  • qdynamicbutton.h – осы сабақта динамикалық объектілермен жұмыс істеу процесін жеңілдететін орауыш класының тақырып файлы;
  • qdynamicbutton.cpp - бұл оқулықтағы динамикалық нысандармен жұмыс істеу процесін жеңілдететін қаптама класының бастапқы файлы.

mainwindow.ui

Бұл оқулықта бізге екі макет қабаты қажет болады. Бір қабатта барлық динамикалық түрде жасалған түймелер болады, ал екінші қабатта динамикалық түймелерді жасау және жою процесіне жауап беретін түймелер, сондай-ақ жасалып жатқан түймелер санын көрсету үшін lineEdit өрісі болады.

Қолданбаның сыртқы түрі Тікелей жұмыс қолданба терезесі нысанының келесі объектілерімен жүзеге асырылады:

  • addButton - динамикалық түймелерді қосу батырмасы;
  • deleteButton - динамикалық түймелерді жою батырмасы;
  • verticalLayout - тік орналасуы бар динамикалық түймелерді қосу қабаты;
  • lineEdit - құрылған түймелердің сандарын көрсету өрісі.

qdynamicbutton.h

QPushButton сыныбынан мұраланған орауыш класының тақырып файлы. Бұл класс сыныптың барлық нысандарына ортақ болатын статикалық айнымалыны жариялайды және келесіде жасалатын барлық динамикалық түймелердің есептегіштері болады. бұл қолданба. Бұл әр түймеге сәйкес сандарды тағайындау үшін қажет.

#ifndef QDYNAMICBUTTON\_H
#define QDYNAMICBUTTON\_H

#include <QPushButton>

class QDynamicButton : public QPushButton
{
    Q\_OBJECT
public:
    explicit QDynamicButton(QWidget *parent = 0);
    ~QDynamicButton();
    static int ResID;   // Статическая переменная, счетчик номеров кнопок
    int getID();        // Функция для возврата локального номера кнопки


public slots:

private:
    int buttonID = 0;   // Локальная переменная, номер кнопки
};

#endif // QDYNAMICBUTTON\_H

qdynamicbutton.cpp

Қаптама класының бастапқы код файлында түйме оның конструкторында инициализацияланады, статикалық айнымалы инициализацияланады, сонымен қатар динамикалық түйменің нөмірін қайтару әдісі бар.

#include "qdynamicbutton.h"

QDynamicButton::QDynamicButton(QWidget *parent) :
    QPushButton(parent)
{
    ResID++;            // Увеличение счетчика на единицу
    buttonID = ResID;   /* Присвоение кнопке номера, по которому будет производиться
                         * дальнейшая работа с кнопок
                         * */

}

QDynamicButton::~QDynamicButton()
{

}

/* Метод для возврата значения номера кнопки
 * */
int QDynamicButton::getID()
{
    return buttonID;
}

/* Инициализация статической переменной класса.
 * Статическая переменная класса должна инициализироваться в обязательном порядке
 * */
int QDynamicButton::ResID = 0;

mainwindow.h

Тақырып файлында басқару түймелерін өңдеуге арналған SLOT және басылған динамикалық түйменің нөмірін алу үшін SLOT қосу керек.

#ifndef MAINWINDOW\_H
#define MAINWINDOW\_H

#include <QMainWindow>

/* My Includes */
#include <qdynamicbutton.h>

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q\_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

private slots:
    void on\_addButton\_clicked();    // СЛОТ-обработчик нажатия кнопки добавления
    void on\_deleteButton\_clicked(); // СЛОТ-обработчик нажатия кнопки удаления
    void slotGetNumber();           // СЛОТ для получения номера нажатой динамической кнопки

private:
    Ui::MainWindow *ui;
};

#endif // MAINWINDOW\_H
mainwindow.cpp

#include "mainwindow.h"
#include "ui\_mainwindow.h"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    /* Для удобства работы слои разделены QSplitter
     * */
    ui->splitter->setStretchFactor(0,1);
    ui->splitter->setStretchFactor(1,0);
}

MainWindow::~MainWindow()
{
    delete ui;
}

/* Метод для добавления динамической кнопки
 * */
void MainWindow::on\_addButton\_clicked()
{
    QDynamicButton *button = new QDynamicButton(this);  // Создаем объект динамической кнопки
    /* Устанавливаем текст с номером этой кнопки
     * */
    button->setText("Кнопочка " + QString::number(button->getID()));
    /* Добавляем кнопку в слой с вертикальной компоновкой
     * */
    ui->verticalLayout->addWidget(button);
    /* Подключаем сигнал нажатия кнопки к СЛОТ получения номера кнопки
     * */
    connect(button, SIGNAL(clicked()), this, SLOT(slotGetNumber()));
}

/* Метод для удаления динамической кнопки по её номеру
 * */
void MainWindow::on\_deleteButton\_clicked()
{
    /* Выполняем перебор всех элементов слоя, где располагаются динамические кнопки
     * */
    for(int i = 0; i < ui->verticalLayout->count(); i++){
        /* Производим каст элемента слоя в объект динамической кнопки
         * */
        QDynamicButton *button = qobject\_cast<QDynamicButton*>(ui->verticalLayout->itemAt(i)->widget());
        /* Если номер кнопки соответствует числу, которое установлено
         * в lineEdit, то производим удаление данной кнопки
         * */
        if(button->getID() == ui->lineEdit->text().toInt()){
            button->hide();
            delete button;
        }
    }
}

/* СЛОТ для получения номера кнопки.
 * */
void MainWindow::slotGetNumber()
{
    /* Определяем объект, который вызвал сигнал
     * */
    QDynamicButton *button = (QDynamicButton*) sender();
    /* После чего устанавливаем номер кнопки в lineEdit,
     * который содержится в данной динамической кнопке
     * */
    ui->lineEdit->setText(QString::number(button->getID()));
    /* То есть номер кнопки устанавливается в поле lineEdit только тогда,
     * когда мы нажимаем одну из динамических кнопок, и этот номер соответствует
     * номеру нажатой кнопки
     * */
}

Барлығы

Нәтижесінде түймелерді динамикалық түрде жасайтын және жойатын қолданба болуы керек. Қолданба төмендегі бейнеде көрсетілген.

Рекомендуем хостинг TIMEWEB
Рекомендуем хостинг TIMEWEB
Стабильный хостинг, на котором располагается социальная сеть EVILEG. Для проектов на Django рекомендуем VDS хостинг.

Ол саған ұнайды ма? Әлеуметтік желілерде бөлісіңіз!

KL
  • Қаң. 26, 2017, 11:13 Т.Ж.
 QDynamicButton *button = qobject_cast<QDynamicButton*>(ui->verticalLayout->itemAt(i)->widget());
Поясните пожалуйста смысл этой строки.
Evgenii Legotckoi
  • Қаң. 26, 2017, 11:22 Т.Ж.

В Qt элементы интерфейса имеют базовый класс QWidget . QDynamycButton наследован от QPushButton , который в свою очередь наследован в конечном итоге от QWidget . Из Layout`а указатели на объекты забираются в качестве указателей на объекты класса QWidget .

Таким образом, чтобы получить доступ к методам класса QDynamicButton , объектами которого являются в данном случае объекты, которые находятся в данном Layout`е, необходимо скастовать указатель из класса QWidget в QDynamicButton

Такие возможности языка C++ достигаются за счёт парадигмы полиморфизма. Пример полиморфизма с некоторыми пояснениями дан в этой статье .

F
  • Мамыр 23, 2018, 8:36 Т.Қ.

Хм, не знаю как у других, а у меня отсутствует метод ui->splitter . Может быть потому что я на линухе сижу

Evgenii Legotckoi
  • Мамыр 24, 2018, 2:12 Т.Ж.

компонент был создан в графическом дизайнере, о чём говорит название объекта ui , в котором находится объект splitter.

Это не имеет зависимости на платформу
H
  • Қар. 1, 2018, 4:23 Т.Ж.

А если я неким неизвестным образом добавил разношерстные элементы в ui: checkbox,radiobutton,textedit и label. Они лежат группами одинаковых (одного типа) объектах в vbox, лежащий в groupbox, который в свою очередь находится в vertical layout. Как бы теперь двойным циклом пройтись по каждому из этих объектов в каждом из этих groupbox?

Evgenii Legotckoi
  • Қар. 1, 2018, 4:28 Т.Ж.

Можно поискать нужные элементы через метод findChildren

QList<QWidget *> widgets = parentWidget.findChildren<QWidget *>("widgetname");

или выбрать все групбоксы, а потом каждом использовать метод findChildren.

Метод шаблонный, поэтому можно попытаться найти например только QLineEdit, вместо QWidget, поскольку QWidget - это базовый класс для QLineEdit и остальных виджетов.

H
  • Қар. 2, 2018, 6:03 Т.Ж.

Т.е. я могу сделать что-то вроде такого?

QList<QGroupBox*> groups = ui->centralWidget->findChildren<QGroupBox*>();
QList<QWidget*> items;
items = groups.at(0)->findChildren<QCheckBox*>();
Когда я пробую такой вариант, происходит ошибка:
candidate function not viable: no known conversion from 'QList<QCheckBox *>' to 'const QList<QWidget *>' for 1st argument, т.е. получается, лист чекбоксов в лист виджетов я все-таки поместить не могу.
Evgenii Legotckoi
  • Қар. 2, 2018, 6:23 Т.Ж.

Вы с ошибкой написали

Надо так

QList<QGroupBox*> groups = ui->centralWidget->findChildren<QGroupBox*>();
QList<QCheckBox*> items;
items = groups.at(0)->findChildren<QCheckBox*>();

H
  • Қар. 2, 2018, 6:27 Т.Ж.

Не, я в смысле думал, что могу использовать родительский класс для этого, т.е. я хотел бы сделать что-то вроде:

  1. QList<QGroupBox*> groups = ui->centralWidget->findChildren<QGroupBox*>();
  2. QList<QWidget*> items;
  3. items = groups.at(0)->findChildren<QCheckBox*>();
  4. if(items.length() != 0) // т.е. если там есть хоть один чекбокс
  5. do smthing;
  6. else items = groups.at(0)->findChildren<QRadioButton*>();
  7. ...
Evgenii Legotckoi
  • Қар. 2, 2018, 6:42 Т.Ж.
  • (өңделген)

То, что вы так хотели сделать, не значит что это работает в С++. Вы не можете присвоить объект QList<QCheckBox*> к объекту QList<QWidget*> - это разные сущности контейнеров, хотя через методы append вы сможете добавить в контейнер другие классы, у которых родительский класс бцдет QWidget, но в данном случае не будет происходит копирование одного контейнера в объект другого.

И вообще, что вам мешает сделать так?

QList<QGroupBox*> groups = ui->centralWidget->findChildren<QGroupBox*>();
if(groups.at(0)->findChildren<QCheckBox*>().length() != 0) // т.е. если там есть хоть один чекбокс
 do smthing;

H
  • Қар. 2, 2018, 6:45 Т.Ж.

Ну да, сейчас я уже буду делать тогда так, просто придется создавать листы под каждый тип виджетов. Спасибо!

Михаиллл
  • Қар. 15, 2018, 7:54 Т.Ж.

Скажите пожалуйста, как в VerticalLayout добавить VerticalSpaser так, чтобы при этом кнопки смещались вверх, а не в низ. Если это сделать в дизайнере, кнопки смещаются вниз, т.к. они добавляются после.

Evgenii Legotckoi
  • Қар. 15, 2018, 8:07 Т.Ж.

используйте метод insertWidget. В нём можно указать индекс, куда добалвять кнопку. Нужно будет найти индекс VerticalSpacer с помощью метода indexOf(verticalSpacer)

и на этот индекс добавлять кнопку.

Михаиллл
  • Қар. 15, 2018, 8:30 Т.Ж.

но у VerticalSpacer нет метода indexOf.

insertWidget использовать вместо addWidget?


Evgenii Legotckoi
  • Қар. 15, 2018, 8:34 Т.Ж.
но у VerticalSpacer нет метода indexOf.

У него нет, а вот у verticalLayout есть. Если вы добавите через дизайнер лейаут и спейсер, то можете забрать индекс спейсера так

ui->verticalLayout->indexOf(ui->verticalSpacer);

Да, использовать insertWidget




Михаиллл
  • Қар. 15, 2018, 8:55 Т.Ж.

у меня выдает ошибку D:\QTProject\ReaderResume\mainwindow.cpp:811: ошибка: cannot initialize a parameter of type 'QWidget *' with an lvalue of type 'QSpacerItem *'

Evgenii Legotckoi
  • Қар. 15, 2018, 8:58 Т.Ж.

А вот про это я забыл... Он же не наследован от QWidget.

Тогда, если вы знаете, что спецсер всегда в конце, то тогда так можете это сделать.

ui->verticalLayout->insertWidget(ui->verticalLayout.count() - 1, widget);


Михаиллл
  • Қар. 15, 2018, 9:45 Т.Ж.

но у verticalLayout нет метода insertWidget

Evgenii Legotckoi
  • Қар. 15, 2018, 9:55 Т.Ж.

verticalLayout - это, по-моему предположению, должен быть у вас объект класса QVBoxLayout, который наследован от QBoxLayout.

Поэтому открываете документацию на QVBoxLayout .

И ищете там строку List of all members, including inherited members это сразу под краткой анотацией класса. Кликаете по этой надписи и переходите на страницу с полным списком всех методов класса QVBoxLayout.

После этого нужно воспользоваться поиском по странице Ctrl+F, чтобы найти insertWidget. И вы увидите, что там есть этот метод.

Если вы всё-таки использовали QGridLayout, то измените класс QVBoxLayout, если вам нужен имен просто вертикальный тип размещения, а не сетка.

Михаиллл
  • Қар. 15, 2018, 10:35 Т.Ж.

Спасибо. Похоже где то описку сделал, поэтому не работало.

Я добавил на verticalLayout много виджитов. А можно ли их как то быстро и просто удалить?


Evgenii Legotckoi
  • Қар. 16, 2018, 1:48 Т.Ж.

пройтись циклом по всем виджетам в обратном порядке

for (int i = ui->vertialLayout->count() - 1; i >= 0; --i)
{
    QWidget* w = ui->verticalLyout->itemAt(i)->widget();
    ui->verticalLayout->removeWidget(w);
    w->deleteLater();
}


P.
  • Мамыр 14, 2019, 6:33 Т.Қ.
  • (өңделген)

Здравствуйте! А не подскажите, как можно при удалении какой либо кнопки, у щётчика отнять значение? Дабы например четвёртой кнопке соответствовал ID 4, а не 5 скажем

Evgenii Legotckoi
  • Мамыр 18, 2019, 5:13 Т.Ж.

Добрый день!

Отнимать значение общего счётчика можно в деструкторе класса кнопки

QDynamicButton::~QDynamicButton()
{
    ResID--;
}

При этом я бы ещё переустанавливал значения всех ID у всех кнопкок, когда была удалена одна из кнопок, дял этого можно написать метод установки ID, который будет называть setButtonID

class QDynamicButton : public QPushButton
{
    Q_OBJECT
public:
    explicit QDynamicButton(QWidget *parent = 0);
    ~QDynamicButton();
    static int ResID;   // Статическая переменная, счетчик номеров кнопок
    int getID();        // Функция для возврата локального номера кнопки

    void setButtonID(int value);    // Установка id и текста

public slots:

private:
    int buttonID = 0;   // Локальная переменная, номер кнопки
};

Вот его релизация

void QDynamicButton::setButtonID(int value)
{
    buttonID = value;
    setText("Кнопочка " + QString::number(buttonID));
}

После чего модифицировать метод удаления кнопок следующим образом

void Widget::on_deleteButton_clicked()
{
    /* Выполняем перебор всех элементов слоя, где располагаются динамические кнопки
     * */
    for(int i = 0; i < ui->verticalLayout->count(); i++){
        /* Производим каст элемента слоя в объект динамической кнопки
         * */
        QDynamicButton *button = qobject_cast<QDynamicButton*>(ui->verticalLayout->itemAt(i)->widget());
        /* Если номер кнопки соответствует числу, которое установлено
         * в lineEdit, то производим удаление данной кнопки
         * */
        if(button->getID() == ui->lineEdit->text().toInt()){
            button->hide();
            delete button;
        }
    }

    for (int i = 0; i < ui->verticalLayout->count(); ++i)
    {
        QDynamicButton *button = qobject_cast<QDynamicButton*>(ui->verticalLayout->itemAt(i)->widget());
        button->setButtonID(i + 1);
    }
}

P.
  • Мамыр 18, 2019, 10:03 Т.Ж.

Спасибо большое! Вскоре буду разбираться!

b
  • Наурыз 29, 2022, 4:16 Т.Қ.
  • (өңделген)

а можно посмотреть финальный проект? Что-то не пойму что я делаю не так

Ruslan Polupan
  • Мамыр 11, 2022, 4:38 Т.Ж.

Добрый день! В какую сторону копать чтобы изменить на кнопке созданной динамически например Иконку основываяь на данных полученных из потока. Ну напрепер функция из потока возвращает true олна иконка, false - другая.

Михаил Сермяжко
  • Мамыр 11, 2022, 4:57 Т.Ж.

Нужно хранить указатели на кнопки или получать их, после чего работать с этим указателем, например задать иконку как то так: указательКнопки->setIcon(QIcon)

Ruslan Polupan
  • Мамыр 11, 2022, 5:15 Т.Ж.

Хотелось бы по подробнее про сохранение.
Вот создаю QLabel в потоке проверяю есть с хостом связь или нет.
Срабатывает только на посдний созданный QLabel.
Т.е Основной поток только его идентифицирует.

for(uint i = 0;i<rowCount; ++i){

        QGroupBox *groupBoxPos = new QGroupBox("Pos ID "+QString::number(i+1),this);
        QHBoxLayout *grBoxLayout = new QHBoxLayout();
        labelStatus = new QLabel();
        grBoxLayout->addWidget(labelStatus);
        groupBoxPos->setLayout(grBoxLayout);
        ui->gridLayout->addWidget(groupBoxPos);


        TestVNCConnect *testVNC = new TestVNCConnect(connList.at(i).at(0), connList.at(i).at(1).toUInt());
        QThread *thread = new QThread();
        testVNC->moveToThread(thread);

        connect(thread,&QThread::started,this,&TestTemplateDialog::slotStartTestVNC);
        connect(thread,&QThread::started,testVNC,&TestVNCConnect::checkConnectionStatus);
        connect(testVNC,&TestVNCConnect::signalSendStatusConnect,this,&TestTemplateDialog::slotGetStatusVNC);
        connect(testVNC,&TestVNCConnect::finish,thread,&QThread::quit);
        connect(testVNC,&TestVNCConnect::finish,this,&TestTemplateDialog::slotFinishTestVNC);
        connect(testVNC,&TestVNCConnect::finish,testVNC,&TestVNCConnect::deleteLater);
        connect(thread,&QThread::finished,thread,&QThread::deleteLater);

        thread->start();
}

void TestTemplateDialog::slotStartTestVNC()
{
    qInfo(logInfo()) << "Show testing" << labelStatus->indent();
    labelStatus->setPixmap(QPixmap(":/Images/connect_creating_icon.png").scaled(QSize(32,32)));
}

void TestTemplateDialog::slotFinishTestVNC()
{
//    qInfo(logInfo()) << "Show result.";
    if(statusVNC){
        labelStatus->setPixmap(QPixmap(":/Images/connect_established_icon.png").scaled(QSize(32,32)));
    } else {
        labelStatus->setPixmap(QPixmap(":/Images/connect_no_icon.png").scaled(QSize(32,32)));
    }
}

void TestTemplateDialog::slotGetStatusVNC(bool status)
{
    statusVNC = status;
}
Михаил Сермяжко
  • Мамыр 11, 2022, 5:18 Т.Ж.

Думаю упускаете важный момент, в Qt можно создавать виджеты и работать с ними только в главном потоке.

Ruslan Polupan
  • Мамыр 11, 2022, 5:23 Т.Ж.

Я из потока получаю только true\false и на основе этого хочу в главном потоке установить ту или иную иконку.

Михаил Сермяжко
  • Мамыр 11, 2022, 5:38 Т.Ж.

Тогда сделайте массив, запихните в него labelStatus, потом уже обращайтесьь к нему как к члену массива и меняйте как хотите

Пікірлер

Тек рұқсаты бар пайдаланушылар ғана пікір қалдыра алады.
Кіріңіз немесе Тіркеліңіз
AD

C++ - Тест 004. Указатели, Массивы и Циклы

  • Нәтиже:50ұпай,
  • Бағалау ұпайлары-4
m
  • molni99
  • Қаз. 26, 2024, 1:37 Т.Ж.

C++ - Тест 004. Указатели, Массивы и Циклы

  • Нәтиже:80ұпай,
  • Бағалау ұпайлары4
m
  • molni99
  • Қаз. 26, 2024, 1:29 Т.Ж.

C++ - Тест 004. Указатели, Массивы и Циклы

  • Нәтиже:20ұпай,
  • Бағалау ұпайлары-10
Соңғы пікірлер
ИМ
Игорь МаксимовҚар. 22, 2024, 11:51 Т.Ж.
Django - Оқулық 017. Теңшелген Django кіру беті Добрый вечер Евгений! Я сделал себе авторизацию аналогичную вашей, все работает, кроме возврата к предидущей странице. Редеректит всегда на главную, хотя в логах сервера вижу запросы на правильн…
Evgenii Legotckoi
Evgenii LegotckoiҚаз. 31, 2024, 2:37 Т.Қ.
Django - Сабақ 064. Python Markdown кеңейтімін қалай жазуға болады Добрый день. Да, можно. Либо через такие же плагины, либо с постобработкой через python библиотеку Beautiful Soup
A
ALO1ZEҚаз. 19, 2024, 8:19 Т.Ж.
Qt Creator көмегімен fb3 файл оқу құралы Подскажите как это запустить? Я не шарю в программировании и кодинге. Скачал и установаил Qt, но куча ошибок выдается и не запустить. А очень надо fb3 переконвертировать в html
ИМ
Игорь МаксимовҚаз. 5, 2024, 7:51 Т.Ж.
Django - Сабақ 064. Python Markdown кеңейтімін қалай жазуға болады Приветствую Евгений! У меня вопрос. Можно ли вставлять свои классы в разметку редактора markdown? Допустим имея стандартную разметку: <ul> <li></li> <li></l…
d
dblas5Шілде 5, 2024, 11:02 Т.Ж.
QML - Сабақ 016. SQLite деректер қоры және онымен QML Qt-та жұмыс істеу Здравствуйте, возникает такая проблема (я новичок): ApplicationWindow неизвестный элемент. (М300) для TextField и Button аналогично. Могу предположить, что из-за более новой верси…
Енді форумда талқылаңыз
m
moogoҚар. 22, 2024, 7:17 Т.Ж.
Mosquito Spray System Effective Mosquito Systems for Backyard | Eco-Friendly Misting Control Device & Repellent Spray - Moogo ; Upgrade your backyard with our mosquito-repellent device! Our misters conce…
Evgenii Legotckoi
Evgenii LegotckoiМаусым 24, 2024, 3:11 Т.Қ.
добавить qlineseries в функции Я тут. Работы оень много. Отправил его в бан.
t
tonypeachey1Қар. 15, 2024, 6:04 Т.Ж.
google domain [url=https://google.com/]domain[/url] domain [http://www.example.com link title]
NSProject
NSProjectМаусым 4, 2022, 3:49 Т.Ж.
Всё ещё разбираюсь с кешем. В следствии прочтения данной статьи. Я принял для себя решение сделать кеширование свойств менеджера модели LikeDislike. И так как установка evileg_core для меня не была возможна, ибо он писался…

Бізді әлеуметтік желілерде бақылаңыз