qt

Описание: Разработка и отладка приложений. Упор на 3D-графику.

dyvniy M
Автор темы, Администратор
Администратор
Аватара
dyvniy M
Автор темы, Администратор
Администратор
Возраст: 41
Репутация: 1
Лояльность: 1
Сообщения: 3579
Зарегистрирован: Ср, 10 октября 2012
С нами: 11 лет 6 месяцев
Профессия: Программист
Откуда: Россия, Москва
ICQ Сайт Skype ВКонтакте

#19 dyvniy » Пт, 26 сентября 2014, 22:25:30

TODO для QtCreator
http://habrahabr.ru/post/101311/
Спойлер
Итак, уже давно уважаемый Евгений писал нам о хаках QtCreator, а также указывал в своем блоге документ с подробной инструкцией по созданию плагина. И вот на этих выходных, будучи на даче, оторванным от цивилизации и интернета, я решил попробовать написать свой плагин. Плагин достаточно прост, он выводит список все TODO, FIXME и т. д. комментариев в текущем открытом документе. Ниже я расскажу про то, как написан этот плагин, и вообще про написание плагинов для QtCreator.
TODO Plugin


Начало

Первое что потребуется для создания плагина, это скачать исходный код QtCreator, это можно сделать здесь. Теперь, нужно распаковать полученный архив и создать новый пустой проект в папке /src/plugins/.

Создаем плагин который ничего не делает

Для этого в проект нужно добавить новый класс, который будет основным классом плагина, он должен наследоваться от интерфейса ExtensionSystem::IPlugin.
Для этого необходимо в .pro файл добавить следующие строки:
include(../../qtcreatorplugin.pri)
include(../../plugins/coreplugin/coreplugin.pri)

Coreplugin нужен, потому что все пользовательские плагины зависят от него, он предоставляет основные интерфейсы для создания других плагинов.

Также потребуется создать xml-файл <имяплагина>.pluginspec следующего формата
<plugin name=«todo» version=«0.0.1» compatVersion=«2.0.0»>
<vendor>vsorokin</vendor>
<copyright>Your copyright</copyright>
<license>Your license</license>
<description>Plugin description</description>
<url>Project homepage</url>
<dependencyList>
<dependency name=«Core» version=«2.0.0»/>
</dependencyList>
</plugin>

Смысл полей понятен из их названия.

Итак, сам класс ничего не делающего плагина должен иметь такую структуру:
#include <extensionsystem/iplugin.h>

class TodoPlugin: public ExtensionSystem::IPlugin
{
Q_OBJECT
public:
TodoPlugin();
~TodoPlugin();
void extensionsInitialized();
bool initialize(const QStringList & arguments, QString * errorString);
void shutdown();
};

* This source code was highlighted with Source Code Highlighter.

Главным здесь является метод initialize, который выполняет инициализацию плагина. Впрочем, в плагине, который ничего не делает, все методы пусты.

Создаем новый Output Pane

Для моего плагина потребовалась новая область вывода, по соседству с уже имеющимися, делается она очень просто, для этого достаточно создать новый класс наследуемый от интерфейса Core::IOutputPane, вот заголовок этого класса:
#include <coreplugin/ioutputpane.h>
#include <QObject>
#include <QListWidget>

class TodoOutputPane: public Core::IOutputPane
{
public:
TodoOutputPane(QObject *parent);
~TodoOutputPane();

QWidget *outputWidget(QWidget *parent); // Возвращает основной виджет класса, здесь это QListWidget
QList<QWidget*> toolBarWidgets() const; // Возвращает список виджетов тулбара, в этом плагине их нет
QString name() const; // Просто текстовое название панели

int priorityInStatusBar() const; // Возвращает число от одного до ста, чем больше число тем более верхнее положение займет наш pane

void clearContents(); // Выполняет очистку основного виджета
void visibilityChanged(bool visible);

void setFocus();
bool hasFocus();
bool canFocus();

bool canNavigate();
bool canNext();
bool canPrevious();
void goToNext();
void goToPrev();

void addItem(QString text, QString file, int rowNumber);// Метод, который вставляет новую запись в список
QListWidget *getTodoList() const; // Указатель на список

private:
QListWidget *todoList;
};

* This source code was highlighted with Source Code Highlighter.


Теперь надо как-то зарегистрировать наш свежесозданный todoPane в системе, для этого в методе initialize пишем такой код:
outPane = new TodoOutputPane(this);
addAutoReleasedObject(outPane);

* This source code was highlighted with Source Code Highlighter.

Все очень просто, теперь наш outPane появится среди остальных, но пока он ничего не может.

Получаем информацию об открытом файле и парсим его

Для того чтобы узнать какой файл сейчас открыт в редакторе, надо как-то достучаться до редактора…
Для этого необходимо добавить следующие заголовки:
#include <coreplugin/editormanager/editormanager.h>
#include <coreplugin/editormanager/ieditor.h>

* This source code was highlighted with Source Code Highlighter.

А в метод initialize добавить следующую строку:
connect(Core::EditorManager::instance(), SIGNAL(currentEditorChanged(Core::IEditor*)), this, SLOT(currentEditorChanged(Core::IEditor*)));

* This source code was highlighted with Source Code Highlighter.

Ну и конечно же объявить слот currentEditorChanged(Core::IEditor*)
Этот слот будет вызываться каждый раз когда изменился текущий редактор, т. е. пользователь открыл/закрыл файл, или перешел к другому уже открытому.
Его реализация такова:
void TodoPlugin::currentEditorChanged(Core::IEditor *editor)
{
outPane->clearContents(); // Очищаем
if (!editor) // Проверяем, а есть ли редактор? вообще
{
return;
}
/* Тонкий момент, соединяем сигнал изменения класса файла привязанного к текущему редактору, чтобы последствии можно было перечитывать файл, после того как пользователь нажал Ctrl+S */
connect(editor->file(), SIGNAL(changed()), this, SLOT(fileChanged()));
QString fileName = editor->file()->fileName(); // Получаем имя файла
readFile(fileName); // читаем и парсим файл.
}

* This source code was highlighted with Source Code Highlighter.

Здесь вызывается метод парсинга, он прост:
void TodoPlugin::readFile(QString fileName)
{
QFile file(fileName);
if (!file.open(QFile::ReadOnly | QFile::Text))
return;
int i = 1;
while (!file.atEnd())
{
QString currentLine = file.readLine();
if (currentLine.contains(QRegExp(patternString, Qt::CaseInsensitive)))
{
outPane->addItem(currentLine, fileName, i);
}
++i;
}
}

* This source code was highlighted with Source Code Highlighter.


Также нужно описать новый слот, который будет вызываться, если файл сохранили, вот он:
void TodoPlugin::fileChanged()
{
outPane->clearContents();
Core::IFile *file = (Core::IFile *)sender(); // Это несколько не православный способ, но он будет вполне безопасно работать, т. к. этому слоту не подключено больше никаких сигналов.
if (file)
{
readFile(file->fileName());
}
}

* This source code was highlighted with Source Code Highlighter.


Добавление строк

Теперь необходимо описать добавление строк, то есть метод:
void TodoOutputPane::addItem(QString text, QString file, int rowNumber)
{
QListWidgetItem *newItem = new QListWidgetItem(); // Создаем новую запись
QRegExp todoExp("//\\s*TODO(:|\\s)", Qt::CaseInsensitive); // Подготавливаем регекспы
QRegExp noteExp("//\\s*NOTE(:|\\s)", Qt::CaseInsensitive);
QRegExp fixmeExp("//\\s*FIXME(:|\\s)", Qt::CaseInsensitive);
QRegExp bugExp("//\\s*BUG(:|\\s)", Qt::CaseInsensitive);
QRegExp hackExp("//\\s*HACK(:|\\s)", Qt::CaseInsensitive);

text = text.replace("\n", "");
text = text.replace("\r", "");

newItem->setTextColor(QColor("#2F2F2F"));
if (text.contains(todoExp)) // Ищем регекспы
{
newItem->setBackgroundColor(QColor("#BFFFC8")); // Устанавливаем цвет записи
text = text.replace(todoExp, «TODO: „); // Заменяем “возможно кривое» написание метки на правильное
newItem->setIcon(QIcon(":/warning")); // Устанавливаем иконку
}
else if (text.contains(noteExp))
{
newItem->setBackgroundColor(QColor("#E2DFFF"));
text = text.replace(noteExp, «NOTE: „);
newItem->setIcon(QIcon(“:/info»));
}
else if (text.contains(bugExp))
{
newItem->setBackgroundColor(QColor("#FFBFBF"));
text = text.replace(bugExp, «BUG: „);
newItem->setIcon(QIcon(“:/error»));
}
else if (text.contains(fixmeExp))
{
newItem->setBackgroundColor(QColor("#FFDFDF"));
text = text.replace(fixmeExp, «FIXME: „);
newItem->setIcon(QIcon(“:/error»));
}
else if (text.contains(hackExp))
{
newItem->setBackgroundColor(QColor("#FFFFAA"));
text = text.replace(hackExp, «HACK: „);
newItem->setIcon(QIcon(“:/info»));
}

newItem->setText(text.trimmed() + " (" + tr(«line „) + QString::number(rowNumber) + “)»); // Устанавливаем текст записи
newItem->setToolTip(file + ":" + QString::number(rowNumber)); // В подсказке будет храниться имя файла и номер строки, это не просто так, ниже расскажу зачем.
todoList->addItem(newItem); // Добавляем запись в список
}

* This source code was highlighted with Source Code Highlighter.


Переход на нужную строку по клику на записи

Единственное, что нам осталось сделать, это реализовать переход на нужную строку.
Для этого потребуется еще один слот, который будет выполняться тогда, когда выделили элемент списка:
void TodoPlugin::gotoToRowInFile(QListWidgetItem *item)
{
int row = 0; // Номер строки
QString file = ""; //Имя файла

/* Получаем информацию из подсказки */
QStringList tmpList = item->toolTip().split(":");
if (tmpList.size() == 2)
{
file = tmpList.at(0);
bool ok;
row = tmpList.at(1).toInt(&ok);
if (!ok)
{
row = 0;
}
}
if (QFileInfo(file).exists()) // Проверяем, а существует ли файл.
{
TextEditor::BaseTextEditor::openEditorAt(file, row); // Принудительно показываем файл, установив курсор в строку с номером row. Для того чтобы эта строка работала, необходимо в зависимостях указать TextEditor plugin, и добавить соответсвующий заголовок
Core::EditorManager::instance()->ensureEditorManagerVisible();
}
}
Изображение

dyvniy M
Автор темы, Администратор
Администратор
Аватара
dyvniy M
Автор темы, Администратор
Администратор
Возраст: 41
Репутация: 1
Лояльность: 1
Сообщения: 3579
Зарегистрирован: Ср, 10 октября 2012
С нами: 11 лет 6 месяцев
Профессия: Программист
Откуда: Россия, Москва
ICQ Сайт Skype ВКонтакте

#20 dyvniy » Пт, 26 сентября 2014, 22:26:05

TODO для QtCreator
http://habrahabr.ru/post/101311/
Спойлер
Итак, уже давно уважаемый Евгений писал нам о хаках QtCreator, а также указывал в своем блоге документ с подробной инструкцией по созданию плагина. И вот на этих выходных, будучи на даче, оторванным от цивилизации и интернета, я решил попробовать написать свой плагин. Плагин достаточно прост, он выводит список все TODO, FIXME и т. д. комментариев в текущем открытом документе. Ниже я расскажу про то, как написан этот плагин, и вообще про написание плагинов для QtCreator.
TODO Plugin


Начало

Первое что потребуется для создания плагина, это скачать исходный код QtCreator, это можно сделать здесь. Теперь, нужно распаковать полученный архив и создать новый пустой проект в папке /src/plugins/.

Создаем плагин который ничего не делает

Для этого в проект нужно добавить новый класс, который будет основным классом плагина, он должен наследоваться от интерфейса ExtensionSystem::IPlugin.
Для этого необходимо в .pro файл добавить следующие строки:
include(../../qtcreatorplugin.pri)
include(../../plugins/coreplugin/coreplugin.pri)

Coreplugin нужен, потому что все пользовательские плагины зависят от него, он предоставляет основные интерфейсы для создания других плагинов.

Также потребуется создать xml-файл <имяплагина>.pluginspec следующего формата
<plugin name=«todo» version=«0.0.1» compatVersion=«2.0.0»>
<vendor>vsorokin</vendor>
<copyright>Your copyright</copyright>
<license>Your license</license>
<description>Plugin description</description>
<url>Project homepage</url>
<dependencyList>
<dependency name=«Core» version=«2.0.0»/>
</dependencyList>
</plugin>

Смысл полей понятен из их названия.

Итак, сам класс ничего не делающего плагина должен иметь такую структуру:
#include <extensionsystem/iplugin.h>

class TodoPlugin: public ExtensionSystem::IPlugin
{
Q_OBJECT
public:
TodoPlugin();
~TodoPlugin();
void extensionsInitialized();
bool initialize(const QStringList & arguments, QString * errorString);
void shutdown();
};

* This source code was highlighted with Source Code Highlighter.

Главным здесь является метод initialize, который выполняет инициализацию плагина. Впрочем, в плагине, который ничего не делает, все методы пусты.

Создаем новый Output Pane

Для моего плагина потребовалась новая область вывода, по соседству с уже имеющимися, делается она очень просто, для этого достаточно создать новый класс наследуемый от интерфейса Core::IOutputPane, вот заголовок этого класса:
#include <coreplugin/ioutputpane.h>
#include <QObject>
#include <QListWidget>

class TodoOutputPane: public Core::IOutputPane
{
public:
TodoOutputPane(QObject *parent);
~TodoOutputPane();

QWidget *outputWidget(QWidget *parent); // Возвращает основной виджет класса, здесь это QListWidget
QList<QWidget*> toolBarWidgets() const; // Возвращает список виджетов тулбара, в этом плагине их нет
QString name() const; // Просто текстовое название панели

int priorityInStatusBar() const; // Возвращает число от одного до ста, чем больше число тем более верхнее положение займет наш pane

void clearContents(); // Выполняет очистку основного виджета
void visibilityChanged(bool visible);

void setFocus();
bool hasFocus();
bool canFocus();

bool canNavigate();
bool canNext();
bool canPrevious();
void goToNext();
void goToPrev();

void addItem(QString text, QString file, int rowNumber);// Метод, который вставляет новую запись в список
QListWidget *getTodoList() const; // Указатель на список

private:
QListWidget *todoList;
};

* This source code was highlighted with Source Code Highlighter.


Теперь надо как-то зарегистрировать наш свежесозданный todoPane в системе, для этого в методе initialize пишем такой код:
outPane = new TodoOutputPane(this);
addAutoReleasedObject(outPane);

* This source code was highlighted with Source Code Highlighter.

Все очень просто, теперь наш outPane появится среди остальных, но пока он ничего не может.

Получаем информацию об открытом файле и парсим его

Для того чтобы узнать какой файл сейчас открыт в редакторе, надо как-то достучаться до редактора…
Для этого необходимо добавить следующие заголовки:
#include <coreplugin/editormanager/editormanager.h>
#include <coreplugin/editormanager/ieditor.h>

* This source code was highlighted with Source Code Highlighter.

А в метод initialize добавить следующую строку:
connect(Core::EditorManager::instance(), SIGNAL(currentEditorChanged(Core::IEditor*)), this, SLOT(currentEditorChanged(Core::IEditor*)));

* This source code was highlighted with Source Code Highlighter.

Ну и конечно же объявить слот currentEditorChanged(Core::IEditor*)
Этот слот будет вызываться каждый раз когда изменился текущий редактор, т. е. пользователь открыл/закрыл файл, или перешел к другому уже открытому.
Его реализация такова:
void TodoPlugin::currentEditorChanged(Core::IEditor *editor)
{
outPane->clearContents(); // Очищаем
if (!editor) // Проверяем, а есть ли редактор? вообще
{
return;
}
/* Тонкий момент, соединяем сигнал изменения класса файла привязанного к текущему редактору, чтобы последствии можно было перечитывать файл, после того как пользователь нажал Ctrl+S */
connect(editor->file(), SIGNAL(changed()), this, SLOT(fileChanged()));
QString fileName = editor->file()->fileName(); // Получаем имя файла
readFile(fileName); // читаем и парсим файл.
}

* This source code was highlighted with Source Code Highlighter.

Здесь вызывается метод парсинга, он прост:
void TodoPlugin::readFile(QString fileName)
{
QFile file(fileName);
if (!file.open(QFile::ReadOnly | QFile::Text))
return;
int i = 1;
while (!file.atEnd())
{
QString currentLine = file.readLine();
if (currentLine.contains(QRegExp(patternString, Qt::CaseInsensitive)))
{
outPane->addItem(currentLine, fileName, i);
}
++i;
}
}

* This source code was highlighted with Source Code Highlighter.


Также нужно описать новый слот, который будет вызываться, если файл сохранили, вот он:
void TodoPlugin::fileChanged()
{
outPane->clearContents();
Core::IFile *file = (Core::IFile *)sender(); // Это несколько не православный способ, но он будет вполне безопасно работать, т. к. этому слоту не подключено больше никаких сигналов.
if (file)
{
readFile(file->fileName());
}
}

* This source code was highlighted with Source Code Highlighter.


Добавление строк

Теперь необходимо описать добавление строк, то есть метод:
void TodoOutputPane::addItem(QString text, QString file, int rowNumber)
{
QListWidgetItem *newItem = new QListWidgetItem(); // Создаем новую запись
QRegExp todoExp("//\\s*TODO(:|\\s)", Qt::CaseInsensitive); // Подготавливаем регекспы
QRegExp noteExp("//\\s*NOTE(:|\\s)", Qt::CaseInsensitive);
QRegExp fixmeExp("//\\s*FIXME(:|\\s)", Qt::CaseInsensitive);
QRegExp bugExp("//\\s*BUG(:|\\s)", Qt::CaseInsensitive);
QRegExp hackExp("//\\s*HACK(:|\\s)", Qt::CaseInsensitive);

text = text.replace("\n", "");
text = text.replace("\r", "");

newItem->setTextColor(QColor("#2F2F2F"));
if (text.contains(todoExp)) // Ищем регекспы
{
newItem->setBackgroundColor(QColor("#BFFFC8")); // Устанавливаем цвет записи
text = text.replace(todoExp, «TODO: „); // Заменяем “возможно кривое» написание метки на правильное
newItem->setIcon(QIcon(":/warning")); // Устанавливаем иконку
}
else if (text.contains(noteExp))
{
newItem->setBackgroundColor(QColor("#E2DFFF"));
text = text.replace(noteExp, «NOTE: „);
newItem->setIcon(QIcon(“:/info»));
}
else if (text.contains(bugExp))
{
newItem->setBackgroundColor(QColor("#FFBFBF"));
text = text.replace(bugExp, «BUG: „);
newItem->setIcon(QIcon(“:/error»));
}
else if (text.contains(fixmeExp))
{
newItem->setBackgroundColor(QColor("#FFDFDF"));
text = text.replace(fixmeExp, «FIXME: „);
newItem->setIcon(QIcon(“:/error»));
}
else if (text.contains(hackExp))
{
newItem->setBackgroundColor(QColor("#FFFFAA"));
text = text.replace(hackExp, «HACK: „);
newItem->setIcon(QIcon(“:/info»));
}

newItem->setText(text.trimmed() + " (" + tr(«line „) + QString::number(rowNumber) + “)»); // Устанавливаем текст записи
newItem->setToolTip(file + ":" + QString::number(rowNumber)); // В подсказке будет храниться имя файла и номер строки, это не просто так, ниже расскажу зачем.
todoList->addItem(newItem); // Добавляем запись в список
}

* This source code was highlighted with Source Code Highlighter.


Переход на нужную строку по клику на записи

Единственное, что нам осталось сделать, это реализовать переход на нужную строку.
Для этого потребуется еще один слот, который будет выполняться тогда, когда выделили элемент списка:
void TodoPlugin::gotoToRowInFile(QListWidgetItem *item)
{
int row = 0; // Номер строки
QString file = ""; //Имя файла

/* Получаем информацию из подсказки */
QStringList tmpList = item->toolTip().split(":");
if (tmpList.size() == 2)
{
file = tmpList.at(0);
bool ok;
row = tmpList.at(1).toInt(&ok);
if (!ok)
{
row = 0;
}
}
if (QFileInfo(file).exists()) // Проверяем, а существует ли файл.
{
TextEditor::BaseTextEditor::openEditorAt(file, row); // Принудительно показываем файл, установив курсор в строку с номером row. Для того чтобы эта строка работала, необходимо в зависимостях указать TextEditor plugin, и добавить соответсвующий заголовок
Core::EditorManager::instance()->ensureEditorManagerVisible();
}
}
Изображение

dyvniy M
Автор темы, Администратор
Администратор
Аватара
dyvniy M
Автор темы, Администратор
Администратор
Возраст: 41
Репутация: 1
Лояльность: 1
Сообщения: 3579
Зарегистрирован: Ср, 10 октября 2012
С нами: 11 лет 6 месяцев
Профессия: Программист
Откуда: Россия, Москва
ICQ Сайт Skype ВКонтакте

#21 dyvniy » Пт, 26 сентября 2014, 22:31:29

Плагин поиска дублирующегося кода
для QtCreator
http://savepearlharbor.com/?p=213785
http://habrahabr.ru/post/213785/
Изображение

dyvniy M
Автор темы, Администратор
Администратор
Аватара
dyvniy M
Автор темы, Администратор
Администратор
Возраст: 41
Репутация: 1
Лояльность: 1
Сообщения: 3579
Зарегистрирован: Ср, 10 октября 2012
С нами: 11 лет 6 месяцев
Профессия: Программист
Откуда: Россия, Москва
ICQ Сайт Skype ВКонтакте

#22 dyvniy » Вс, 9 ноября 2014, 23:12:15

Опять QTreeView & QModelIndex
http://www.prog.org.ru/index.php?topic=16459.0
Спойлер
Использую QStandardItemModel в качестве модели (setModel), а QTreeView в качестве представления (setView) для QCombobox. Каждому элементу комбобокса QStandardItem* item назначаю идентификатор через
Код
C++ (Qt)
item->setData(id);
В общем задача перебрать все элементы, найти и сделать текущим элемент с определённым id_ext == item->data(id). Что-то запутался в 3-х соснах. Прочитал QComboBox и его view и другие темы, но пока не разобрался как реализовать.

Обратное преобразование, получить data() == id, текущего комбобокса делаю так:
Код
C++ (Qt)
QModelIndex index = combobox->view()->currentIndex();
QStandardItem *item = ((QStandardItemModel *)combobox->model())->itemFromIndex(index);
currentId = item->data().toInt();
« Последнее редактирование: Январь 24, 2011, 10:25 от AlekseyK » Записан
AlekseyK
Гость

Re: Выделение элемента в QCombobox с QTreeView в качестве пред&
« Ответ #1 : Январь 24, 2011, 02:16 »
Пока сделал так:
Код
C++ (Qt)
void MyProjectBox::selectItemByProjectId(int id)
{
QStandardItemModel *m_pModel = (QStandardItemModel *)model();
QTreeView *m_pView = (QTreeView *)view();

// Select item with specified id in combobox
if(id == -1)
{
QModelIndex index = m_pModel->index(0, 0);
m_pView->setCurrentIndex(index);
}
else
{
for(int i = 0; i < m_pModel->rowCount(); i++)
{
QModelIndex parentIndex = m_pModel->index(i, 0);
int childCount = m_pModel->rowCount(parentIndex);
for(int j = 0; j < childCount; j++)
{
QModelIndex childIndex = m_pModel->index(j, 0, parentIndex);
QStandardItem *item = m_pModel->itemFromIndex(childIndex);
if(item->data().toInt() == id)
{
setRootModelIndex(parentIndex);
setCurrentIndex(j);
setRootModelIndex(QModelIndex());
qDebug() << "id:" << id << "\t(" << i << "," << j << ")";
return;
}
}
}
}
}
Работает, элемент корректно находит, и выделяет его корректно в соответствии с советом вышеозначенных товарищей:
Код
C++ (Qt)
setRootModelIndex(parentIndex);
setCurrentIndex(j); // j - child tree row
setRootModelIndex(QModelIndex());

m_pView->setCurrentIndex(childIndex) не работает.

Подозреваю, что и обратное преобразование нужно выполнять аналогично - вылетает пока. Причём, что интересно вылетает на том комбобоксе, где текущее значение установлено программно, а там где пользователь выбрал пункт в комбобоксе - возвращает правильный индекс и id. В чём может быть проблемаНепонимающий
« Последнее редактирование: Январь 24, 2011, 03:14 от AlekseyK » Записан
AlekseyK
Гость

Re: Выделение элемента в QCombobox с QTreeView в качестве представления
« Ответ #2 : Январь 24, 2011, 03:41 »
Ага, понятно: я зря m_pView->setCurrentIndex(childIndex) выкинул, для выделения элемента программно корректно работает только следующая связка:

combobox->setCurrentIndex() + combobox->view()->setCurrentIndex():

Код
C++ (Qt)
setRootModelIndex(parentIndex);
setCurrentIndex(j); // j - child tree row
setRootModelIndex(QModelIndex());
m_pView->setCurrentIndex(childIndex); // Need to explicit select current index
// in a view to properly select comobobox item
// programmatically
Изображение

dyvniy M
Автор темы, Администратор
Администратор
Аватара
dyvniy M
Автор темы, Администратор
Администратор
Возраст: 41
Репутация: 1
Лояльность: 1
Сообщения: 3579
Зарегистрирован: Ср, 10 октября 2012
С нами: 11 лет 6 месяцев
Профессия: Программист
Откуда: Россия, Москва
ICQ Сайт Skype ВКонтакте

#23 dyvniy » Пн, 17 ноября 2014, 16:37:19

Стили визуального оформления
http://www.cyberforum.ru/qt/thread748173.html
Спойлер
Здравствуйте!

Не могу найти информацию, не знаю как правильно поставить вопрос гуглу...

Опишу ситуацию:
1) Есть проект, на нём куча виджетов... Для примера, пусть будут лабели с
именами "VIS_rec", "VIS_nam", "VIS_...",... (у этой группы у всех есть "VIS_")
Вопрос: как в css файле мне прописать стиль для всей группы: CSS по образцу?,
типа QLabel#[VIS_*] или как-то так QLabel#VIS_[0-9][a-z,A-Z] - в общем не знаю!

Код: Выделить всё

/* как вариант, может можно как-то привязаться к к какому-либо своему свойству?*/
QLabel#[Group="VIS"] /* синтаксис здесь мне тоже не известен... */  
/* просто виджетов очень много и не охота их все перечислять = тяжкое решение*/
QLabel#VIS_1,QLabel#VIS_2,QLabel#VIS_ ...
{
// сам стиль
}
 
2) Как в Linux для QtCreatora в настройках Дизайнера добавить шаблоны, а ещё лучьше
где их можно скачать уже готовые (где их много бесплатных) и будет ли при этом мне
обеспечиваться переносимость исходников проекта на другие машины по стилям???
(в win сам QtCreator запускал с опциями натравления на свой файл стилей по умолчанию)

3) Где же лучше подключать css файл: в конструкторах форм, или в main функции?
Как его перепрочитать в проекте в горячую (на лету) или даже переключится на другой файл?

Спасибо!
AdAgent
Объявления
27.12.2012, 19:29 Qt 4.8 / Оформление проекта и CSS
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
27.12.2012, 19:29 Qt 4.8 / Оформление проекта и CSS
Посмотрите здесь:

C++ Qt Сборка проекта
C++ Qt сборка проекта
C++ Qt Одно оформление для всех операционных систем
C++ Qt Сборка проекта
C++ Qt сборка проекта
C++ Qt перенос проекта с 4.7 на 5.2
C++ Qt Компиляция проекта на Qt (С++)
C++ Qt Оформление QTreeWidget
Kojt
Форумчанин
71 / 67 / 1
Регистрация: 19.05.2010
Сообщений: 167
28.12.2012, 08:40 Qt 4.8 / Оформление проекта и CSS #2
К сожалению могу подсказать только, что у всех виджетов есть функция setStyleSheet

чтобы переключить на другой стиль все приложение надо использовать конструкцию:
Код C++ (QT)
1

Код: Выделить всё

qApp->setStyleSheet(<Тут целиком вычитанный файл стиля в виде одной строки>) 

Стиль можно переносить на другие машины, он не зависит от ОС.
Подключать лучше где удобнее, так же как и с формированием форм, кто-то в коде это руками делает, кто-то в дизайнере.

А где скачать готовые бесплатные стили для оформления программ под Qt меня тоже очень интересует

Полупрозрачный виджет
http://hashcode.ru/questions/110345/c-полупрозрачный-фон-виджета-в-qt
Спойлер
Надо расширить класс QLabel и в новом классе переопределить метод paintEvent, вставив туда примерно такой код

Код: Выделить всё

QPainter paint; 
paint
.begin (this);
paint.setBrush (QBrush (QColor (255, 255, 255, 180)));
paint.setPen (Qt::NoPen);
paint.drawRect (0, 0, width(), height());   
paint
.end();
В QColor последнее значение - значение альфа-канала, которое и определяет прозрачность. Меняется от 0 (полностью прозрачное) до 255.

ссылка
отвечен 16 Май '12 4:16
mikillskegg's gravatar image
mikillskegg
18.4k●8●35
изменен 16 Май '12 4:17
Согласен, что надо делать не средствами окна (setWindowOpacity), а средствами рисования (в paintEvent). Добавлю только что можно использовать свойства QPixmap, QBitmap и можно будет делать прозрачными участки картинки в зависимости от цвета.

И ещё
http://blog.ufna.ru/?p=1099
Спойлер
QT: ПОЛУПРОЗРАЧНЫЕ ОКНА (С ГРАДИЕНТОМ)
Многие из тех, кто имел дело с созданием интерфейса, периодически задумывались о своем кастомном красивом дизайне и нетрадиционной форме окна, к примеру с тенью, полупрозрачностью, округлостями и тому подобным. Ну если не сами задумывались, то заказчики то уж точно попадались, я знаю.

Какое-то время назад эта задача была достаточно сложной, и с точки зрения к примеру GDI до сих пор является велосипедом. Однако Qt предоставляет нам отличную возможность для создания любых интерфейсов.

К примеру, для демонстрации возможностей я взял обыкновенный градиент от черного к белому-прозрачному, созданный в Paint.NET (надеюсь все понимают, что разницы в том, создал я картинку во внешнем редакторе или сгенерировал в программе для данного примера нет никакой).



Моя программа — обычный виджет, который загружает в себя эту картинку и правильным образом ее отрисовывает. Как пример результата, получаем что-то подобное (виджет-картинка выше запущен поверх QtCreator):



Это лишь демонстрация возможностей — надеюсь, вы прекрасно понимаете, что если такой градиент работает как надо, то можно сделать любой по сложности интерфейс, используя полупрозрачность, тени, нестандартные формы на основе этого и т.п.

А теперь — решение задачи применительно к программированию и Qt. На самом деле все просто. Кроме того, что виджет рисует на себе изображение с альфа-каналом, я просто добавил две строчки в конструкторе виджета:

1
setAttribute(Qt::WA_TranslucentBackground);
2
setWindowFlags(Qt::FramelessWindowHint);
Вторая строка обязательна — данный прием не будет работать, если окно будет содержать системную рамку. Хотя в общем-то ради изменения этой рамки на что-то свое и уникальное все это и затеивалось.

Этот прием на самом деле открывает широкое поле для создания виджетов на рабочем столе для всяких развлекательных и информационных нужд — будь то пузырьки с прогнозом погоды или пляшущее солнышко.

COMMENTS

avatar
Сыр Российский 01-10-2010, 09:16
Скриншот непонятный. Покажи, как через твоё окно просвечивает что-нибудь другое, а не только Бездонная Чернота.

Reply
avatar
ufna 01-10-2010, 09:22
Ну я для теста делал такое окно: http://blog.ufna.ru/wp-content/uploads/2010/09/Безымянный.jpg

Для статьи получилось некрасиво, заменил градиентом :)

На скрине также есть ссылочка на скомпилированный пример — там окно можно поперемещать. Двойной клик — закрывает окно.

Reply
avatar
Максим 06-02-2011, 23:40
Небольшая поправочка:
согласно документации флаг Qt::FramelessWindowHint необходим только под Windows.
>:»On Windows the widget also needs the Qt::FramelessWindowHint window flag to be set.»

Reply
avatar
ufna 16-02-2011, 20:09
Точно, спасибо :)

Reply
avatar
anon 15-02-2011, 00:35
Надо добавить, что это будет работать только с композитным WM
А теперь — решение задачи применительно к программированию и Qt. На самом деле все просто. Кроме того, что виджет рисует на себе изображение с альфа-каналом, я просто добавил две строчки в конструкторе виджета:

Код: Выделить всё

setAttribute(Qt::WA_TranslucentBackground);
setWindowFlags(Qt::FramelessWindowHint);
 

Вторая строка обязательна — данный прием не будет работать, если окно будет содержать системную рамку. Хотя в общем-то ради изменения этой рамки на что-то свое и уникальное все это и затеивалось.
Изображение

dyvniy M
Автор темы, Администратор
Администратор
Аватара
dyvniy M
Автор темы, Администратор
Администратор
Возраст: 41
Репутация: 1
Лояльность: 1
Сообщения: 3579
Зарегистрирован: Ср, 10 октября 2012
С нами: 11 лет 6 месяцев
Профессия: Программист
Откуда: Россия, Москва
ICQ Сайт Skype ВКонтакте

Делегаты

#24 dyvniy » Вс, 23 ноября 2014, 16:38:53

Официальная документация
http://doc.qt.io/qt-5/model-view-programming.html#delegate-classes

Отображение собственного виджета в QListView
http://asinenko.com/qwidget-i-qlistview/
Изображение
Спойлер
В примере показано как отобразить свой виджет в QListView. Результат будит такой:



Итак, для начала определим класс в котором будут храниться данные, для отображения в одном виджете. Для того чтоб с ним мог работать класс QVariant его нужно декларировать в окружении, это делается с помощью Q_DECLARE_METATYPE. Т.к. мы будим работать с указателями на объект, то нужно в файле класса написать Q_DECLARE_METATYPE(MyItem *).

myitem.h:


Код: Выделить всё

#ifndef MYITEM_H
#define MYITEM_H
 
#include <QtCore>
 
class MyItem
{
public:
    QString name; // имя
    QString description; // описание
    MyItem();
};
/* в этой строке регистрируем наш тип,
 * для того чтобы с ним мог работать тип QVariant*/
Q_DECLARE_METATYPE(MyItem *)
#endif // MYITEM_H

Далее создаем свой виджет, который нужно отобразить в списке. В примере создается обычный виджет состоящий из двух QLabel.

mylistitemwidget.h:


Код: Выделить всё

#ifndef MYLISTITEMWIDGET_H
#define MYLISTITEMWIDGET_H
 
#include <QWidget>
#include <QLabel>
#include <QVBoxLayout>
 
class MyListItemWidget : public QWidget
{
    Q_OBJECT
public:
    QLabel *name; // поле для MyItem::name
    QLabel *description; // поле для MyItem::description
    QVBoxLayout *layout;
    explicit MyListItemWidget(QWidget *parent = 0);
signals:
 
public slots:
 
};
 
#endif // MYLISTITEMWIDGET_H

Далее, собственно, создание виджета. Имя выделяем жирным шрифтом.

mylistitemwidget.cpp:

Код: Выделить всё

#include "mylistitemwidget.h"
 
MyListItemWidget::MyListItemWidget(QWidget *parent) :
    QWidget(parent)
{
    name = new QLabel;
    description = new QLabel;
    layout = new QVBoxLayout;
    layout->addWidget(name);
    layout->addWidget(description);
    QFont font;
    font.setBold(true);
    name->setFont(font);
    this->setLayout(layout);
}

Чтобы отобразить список, нужно создать свою модель. Если нужно только отображать виджет, то достаточно переопределить лишь некоторые методы: rowCount, data, flags. Список list — это список указателей на объекты класса MyItem.

mylistmodel.h:

Код: Выделить всё

#ifndef MYLISTMODEL_H
#define MYLISTMODEL_H
 
#include <QAbstractListModel>
#include <QList>
 
#include "myitem.h"
 
class MyListModel : public QAbstractListModel
{
    Q_OBJECT
public:
    explicit MyListModel(QObject *parent = 0);
    QList<MyItem *> list;
    int rowCount(const QModelIndex &parent = QModelIndex()) const;
    QVariant data(const QModelIndex &index, int role) const;
    Qt::ItemFlags flags(const QModelIndex &index) const;
signals:
 
public slots:
 
};
 
#endif // MYLISTMODEL_H

Метод data() возвращает QVariant, и для того чтобы вернуть указатель на структуру данных нужно написать:

QVariant::fromValue(list.at(index.row()));

mylistmodel.cpp:

Код: Выделить всё

#include "mylistmodel.h"
 
MyListModel::MyListModel(QObject *parent) :
    QAbstractListModel(parent)
{
}
 
int MyListModel::rowCount(const QModelIndex &parent) const
{
    return list.size();
}
 
QVariant MyListModel::data(const QModelIndex &index, int role) const
{
    if (!index.isValid())
        return QVariant();
    if (index.row() >= list.size())
        return QVariant();
    if (role == Qt::DisplayRole){
        /* Чтобы произвести преобразования QVariant::fromValue(list.at(index.row()))
         * нужно было регистрировать наш тип макросом Q_DECLARE_METATYPE(MyItem *)
         */
        return QVariant::fromValue(list.at(index.row()));
    }else{
        return QVariant();
    }
}
 
Qt::ItemFlags MyListModel::flags(const QModelIndex &index) const
{
    if (!index.isValid())
        return Qt::ItemIsEnabled;
    return QAbstractItemModel::flags(index) | Qt::ItemIsEnabled ;
}

Как для редактирования, так и для отображения данных модели в QListView нужно использовать делегаты. Т.к. в примере не редактируются данные, а только отрисовываются, то нужно только переопределить два метода: paint, в котором и происходит отрисовка виджета; и sizeHint, в котором задаются размеры виджета.

myitemdelegate.h:

#ifndef MYITEMDELEGATE_H
#define MYITEMDELEGATE_H

Код: Выделить всё

#include <QItemDelegate>
#include <QPainter>
 
#include "mylistitemwidget.h"
#include "myitem.h"
 
class MyItemDelegate : public QItemDelegate
{
public:
    MyItemDelegate();
    MyListItemWidget *wdg;
    /*Метод для отрисовки нашего виджета*/
    void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;
    /*Возвращает нужный размер нашего виджета*/
    QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const;
};
 
#endif // MYITEMDELEGATE_H

В методе paint сначала получаем QVariant из метода data(), а затем из QVariant извлекаем указатель на класс MyItem методом QVariant::value(). В общем виде это выглядит так:

MyItem *my_item = index.data().value<MyItem *>();

Далее полученные данные устанавливаем в виджет wdg, ставим нужный фон для выделенного и не выделенного элемента, в примере применяется градиент для большей красоты.

Для отрисовки нужно сначала сохранить состояние painter методом save(), далее отрисовать виджет и востановить состояние painter методом restore():

painter->save();

painter->translate(option.rect.topLeft());

wdg->render(painter);

painter->restore();

myitemdelegate.cpp:

Код: Выделить всё

#include "myitemdelegate.h"
 
MyItemDelegate::MyItemDelegate()
{
    wdg = new MyListItemWidget;
}
 
void MyItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    /* Чтобы произвести данные преобразования нужно было регистрировать
     * тип макросом Q_DECLARE_METATYPE(MyItem *)
     */
    MyItem *my_item = index.data().value<MyItem *>();
    wdg->name->setText(my_item->name);
    wdg->description->setText(my_item->description);
 
    QPalette pal;
    QLinearGradient gradient(0, 0, 0, 100);
 
    /* Если элемент выделен то устанавливаем определенный цвет,
     * если нет, то устанавливаем градиент
     */
    if ((option.state & QStyle::State_Selected) == QStyle::State_Selected){
        pal.setBrush(QPalette::Window, QBrush(QColor(0, 255, 200)));
    }else{
        gradient.setColorAt(0.0, QColor(255,250,0));
        gradient.setColorAt(1.0, QColor(255,255,255));
        pal.setBrush(QPalette::Window, QBrush(QColor(Qt::transparent)));
        pal.setBrush(QPalette::Window, QBrush(gradient));
    }
    wdg->setPalette(pal);
    wdg->resize(option.rect.size());
    /* сохраняем текущее состояние painter'а, для того
     * чтобы произветси изменения над ним */
    painter->save();
    painter->setRenderHint(QPainter::Antialiasing, true);
    painter->translate(option.rect.topLeft());
    wdg->render(painter);
    /*востанавливаем состояние пеинтера*/
    painter->restore();
}
 
QSize MyItemDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    /*указываем любой нужный для нас размер*/
    int width = 100;
    int height = 65;
    return QSize(width, height);
}

В MainWindow ничего особенного не делаем:

Код: Выделить всё

#ifndef MAINWINDOW_H
#define MAINWINDOW_H
 
#include <QMainWindow>
#include <QListView>
#include <QList>
 
#include "mylistmodel.h"
#include "myitem.h"
#include "myitemdelegate.h"
 
class MainWindow : public QMainWindow
{
    Q_OBJECT
public:
    MainWindow(QWidget *parent = 0);
    ~MainWindow();
private:
    MyListModel *model;
    QListView *view;
};
 
#endif // MAINWINDOW_H

Далее создаем список элементов, и устанавливаем его в модель, и т.д…

mainwindow.cpp:

Код: Выделить всё

#include "mainwindow.h"
 
MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
{
    model = new MyListModel;
    view = new QListView;
 
    QList<MyItem *> lst;
 
    MyItem *item1 = new MyItem;
    item1->name = QString::fromUtf8("Название 1");
    item1->description = QString::fromUtf8("Описание 1");
    MyItem *item2 = new MyItem;
    item2->name = QString::fromUtf8("Название 2");
    item2->description = QString::fromUtf8("Оприсание 2");
    MyItem *item3 = new MyItem;
    item3->name = QString::fromUtf8("Название 3");
    item3->description = QString::fromUtf8("Описание 3");
    MyItem *item4 = new MyItem;
    item4->name = QString::fromUtf8("Название 4");
    item4->description = QString::fromUtf8("Описание 4");
 
    lst.append(item1);
    lst.append(item2);
    lst.append(item3);
    lst.append(item4);
 
    model->list = lst; // устанавливаем список элементов
    view->setModel(model); // устанавливаем модель
    view->setItemDelegate(new MyItemDelegate); // устанавливаем делегат
    this->setCentralWidget(view);
}

Все стандартно main.cpp:

Код: Выделить всё

#include <QApplication>
#include "mainwindow.h"
 
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show();
 
    return a.exec();
}


Исходники примера можно скачать тут.




# 03.10.2012, 13:00
8 Comments
Comments

Bobur:
Большое вам спасибо. Много искал и нашел. Эта самый хороший пример для понимая работы с делегатами. Мне очень помогло.

09.07.2013, 06:45 Ответить

Bobur:
Здравствуйте. Можете помогать, как сделать так, чтобы при нажатии кнопки добавился новый MyItem в model? Заранее спасибо.

11.07.2013, 04:02 Ответить

admin:
Добрый день.
Можно несколькими способами добавлять данные в модели
1. Использовать стандартные переопределенные методы(insertRows, setData и т.д.).
2. А можно в классе модели сделать свой метод который будит добавлять данные или производить другие действия. Только для вызова своего метода нужно будит использовать dynamic_cast (http://asinenko.com/qabstractitemmodel-rtti/)

главное в конце нужно не забыть посигналить dataChanged() иначе данные не отобразятся.

лучше, конечно, использовать стандартные методы. Сначала вставить пустую строку а затем установить нужные данные.

11.07.2013, 05:19 Ответить

Bobur:
Я уже прочитал об insertRows() и setData(), но не могу реализовать для данного случая. Можете показать реализацию этих 2х функций для MyItem?

11.07.2013, 06:07 Ответить

Bobur:
Здравствуйте. Извините, что еще раз беспокоил. Можете показать мои ошибки, тут:
bool MyListModel::setData(int row, MyItem *item)
{
if (row > rowCount())
return false;
list[row]->name = item->name;
list[row]->description = item->description;
emit dataChanged(QModelIndex(),QModelIndex());
return true;
}
Программа компилируется и запускается, но windows7 сразу выдает ошибка и спрашивает закрытие. Заранее спасибо за ответ.

12.07.2013, 01:57 Ответить

admin:
Добрый день, прости что не ответил, времени свободного не было совсем. Если именно винда выдает ошибки(тупо выбивает), то в первую очередь нужно искать ошибки в указателях. Очень рекомендую разобраться с дебагером, он поможет найти место где выбивает. Да и вообще, дебагер — наше всё.

04.08.2013, 06:17 Ответить

Максим:
Здравствуйте, можно ли обойтись без QVariant?
Сейчас пишу приложение, используя mips компилятор,с QVariant он явно не дружит, другие компиляторы без проблем собирают мой проект.

06.09.2013, 08:11 Ответить

admin:
Добрый день. Из параметров функций избавиться врятли получится, а вот для приведение к какому-нибудь типу можно попроботать rtti. В частности dynamic_cast. А еще лучше посмотреть в исходниках QVariant как там реализовано приведение к типам. И использовать такой же метод.

06.09.2013, 09:07
http://www.cyberforum.ru/qt/thread625044.html
Вложения
ownWidgetDelegateExample.zip
(44.31 КБ) 122 скачивания
Изображение


Название раздела: Программирование (под Desktop и Android)
Описание: Разработка и отладка приложений. Упор на 3D-графику.

Быстрый ответ


Введите код в точности так, как вы его видите. Регистр символов не имеет значения.
Код подтверждения
:) ;) :hihi: :P :hah: :haha: :angel: :( :st: :_( :cool: 8-| :beee: :ham: :rrr: :grr: :* :secret: :stupid: :music: Ещё смайлики…
   

Вернуться в «Программирование (под Desktop и Android)»

Кто сейчас на форуме (по активности за 15 минут)

Сейчас этот раздел просматривают: 12 гостей