Copy text into another application - qt

I want to emulate a barcode reader and copy barcode content (text) from my application to another application.
I have just found a method to select application window an paste keyCode.
It works with F1 Key fine, but with another key not. (I have tried Tab and space) I think that, Focus is not in text area.
HWND mywindow = ::FindWindow(NULL, L"test.txt - Editor");
uint keyCode;
QString str;
SetForegroundWindow(mywindow);
keyCode = VK_F1; // F1 key
PostMessage(mywindow, WM_KEYDOWN, keyCode, 0); // key down
PostMessage(mywindow, WM_KEYUP, keyCode, 0); // key up

If the content is the text, you could use the SendMessage() to send WM_CHAR to the target window.
Also note that the window should be the edit window or the other child window which need to get the WM_CHAR, use the Notepad as example:
#include <iostream>
#include <Windows.h>
int main()
{
HWND hWndParent = FindWindowW(NULL, L"test.txt - Notepad");
HWND hwnd = FindWindowExW(hWndParent, NULL, L"Edit", NULL);
char str[] = "test_text";
for (int i = 0; i < strlen(str); i++)
{
SendMessage(hwnd, WM_CHAR, str[i], 0);
}
return 0;
}

Related

A best way to draw a lot of independent characters in Qt5?

I'm writing an application that displays a lot of text. It's not words and sentences though, it's binary data displayed in CP437 charset. Current form:
I'm having a problem though with drawing those characters. I need to draw each character one by one, because later I would like to apply different coloring. Those characters should have a transparent background as well, because later I would like to draw sections and ranges with different colors in the background (to group those characters based on some criteria).
The application supports multiple opened files at the same time, but when there are multiple files opened, the drawing starts to be noticeable on fast i7, so it's probably badly written.
What would be the best approach to draw this kind of data in Qt5? Should I just prerender characters to a bitmap and start from there, or it actually is possible to draw lots of characters by using normal Qt functions to draw text?
Edit: I'm using a normal QFrame widget that does drawing in paintEvent, using QPainter. Is this a wrong approach? I've read some docs on QGraphicsScene, from which I've remembered that it's best used in situations where a widget needs to have some control on the objects it draws. I don't need any control on what I draw; I just need to draw it and that's all. I won't reference any particular character after I'll draw it.
The widget has 2000 lines, so I won't paste the whole code, but currently my drawing approach is like this:
First, create a table (cache) with 256 entries, put the iterator counter to i variable,
For each entry, create a QStaticText object that contains drawing information about a character identified by ASCII code taken from i variable,
Later, in the drawing function, for each byte in the input stream (i.e. from the file), draw the data using QStaticText from the cache table. So, to draw ASCII character 0x7A, I'll look up QStaticText from index 0x7a in cache table, and feed this QStaticText object into the QPainter object.
I was also experimenting with a different approach, rendering the whole line in one QPainter::drawText call, and indeed it was faster, but I've lost possibility of coloring each character with different color. I would like to have this possibility.
The use of a QGraphicsScene wouldn't improve things - it's an additional layer on top of a QWidget. You're after raw performance, so you shouldn't be using it.
You could implement a QTextDocument as a viewmodel for the visible section of your memory buffer/file, but painting the fresh QTextDocument each time you scroll wouldn't be any faster than drawing things directly on a QWidget.
Using QStaticText is a step in the right direction, but insufficient: rendering QStaticText still requires the rasterization of the glyph's shape. You can do better and cache the pixmap of each QChar, QColor combination that you wish to render: this will be much faster than rasterizing character outlines, whether using QStaticText or not.
Instead of drawing individual characters, you then draw pixmaps from the cache. This commit demonstrates this approach. The character drawing method is:
void drawChar(const QPointF & pos, QChar ch, QColor color, QPainter & p) {
auto & glyph = m_cache[{ch, color}];
if (glyph.isNull()) {
glyph = QPixmap{m_glyphRect.size().toSize()};
glyph.fill(Qt::white);
QPainter p{&glyph};
p.setPen(color);
p.setFont(m_font);
p.drawText(m_glyphPos, {ch});
}
p.drawPixmap(pos, glyph);
}
You could also cache each (character,foreground,background) tuple. Alas, this gets quickly out of hand when there are many foreground/background combinations.
If all of your backgrounds are of the same color (e.g. white), you'd wish to store a negative mask of the character: the glyph has a white background and a transparent shape. This commit demonstrates this approach. The glyph rectangle is filled with glyph color, then a white mask is applied on top:
void drawChar(const QPointF & pos, QChar ch, QColor color, QPainter & p) {
auto & glyph = m_glyphs[ch];
if (glyph.isNull()) {
glyph = QImage{m_glyphRect.size().toSize(), QImage::Format_ARGB32_Premultiplied};
glyph.fill(Qt::white);
QPainter p{&glyph};
p.setCompositionMode(QPainter::CompositionMode_DestinationOut);
p.setFont(m_font);
p.drawText(m_glyphPos, {ch});
}
auto rect = m_glyphRect;
rect.moveTo(pos);
p.fillRect(rect, color);
p.drawImage(pos, glyph);
}
Instead of storing a fully pre-rendered character of a given color, you could store just the alpha mask and composite them on-demand:
Start with a pre-rendered white glyph on a transparent background (CompositionMode_Source).
Fill the glyph rect with background in CompositionMode_SourceOut: the background will remain with a hole for the character itself.
Fill the glyph rect with foreground in CompositionMode_DestinationOver: the foreground will fill the hole.
(Optional) Draw the composite on the widget, if you're not painting on the widget already.
This turns out to be reasonably fast, and the rendering is fully parallelizable - see the example below.
Note: The pre-rendered glyph could use further premultiplication of the color with alpha to appear less thick.
Yet another approach, with excellent performance, would be to emulate a text-mode display using the GPU. Store the pre-rendered glyph outlines in a texture, store the glyph indices and colors to be rendered in an array, and use OpenGL and two shaders to do the rendering. This example might be a starting point to implement such an approach.
A complete example, using CPU rendering across multiple threads, follows.
We start with the backing store view, used to produce QImages that are views into the backing store for a given widget, and can be used to parallelize painting.
On a 2013 iMac, this code repaints the full-screen widget in about 8ms.
// https://github.com/KubaO/stackoverflown/tree/master/questions/hex-widget-40458515
#include <QtConcurrent>
#include <QtWidgets>
#include <algorithm>
#include <array>
#include <cmath>
struct BackingStoreView {
QImage *dst = {};
uchar *data = {};
const QWidget *widget = {};
explicit BackingStoreView(const QWidget *widget) {
if (!widget || !widget->window()) return;
dst = dynamic_cast<QImage*>(widget->window()->backingStore()->paintDevice());
if (!dst || dst->depth() % 8) return;
auto byteDepth = dst->depth()/8;
auto pos = widget->mapTo(widget->window(), {});
data = const_cast<uchar*>(dst->constScanLine(pos.y()) + byteDepth * pos.x());
this->widget = widget;
}
// A view onto the backing store of a given widget
QImage getView() const {
if (!data) return {};
QImage ret(data, widget->width(), widget->height(), dst->bytesPerLine(), dst->format());
ret.setDevicePixelRatio(widget->devicePixelRatio());
return ret;
}
// Is a given image exactly this view?
bool isAView(const QImage &img) const {
return data && img.bits() == data && img.depth() == dst->depth()
&& img.width() == widget->width() && img.height() == widget->height()
&& img.bytesPerLine() == dst->bytesPerLine() && img.format() == dst->format();
}
};
Then, the CP437 character set:
static auto const CP437 = QStringLiteral(
" ☺☻♥♦♣♠•◘○◙♂♀♪♫☼▶◀↕‼¶§▬↨↑↓→←∟↔▲▼"
"␣!\"#$%&'()*+,-./0123456789:;<=>?"
"#ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_"
"`abcdefghijklmnopqrstuvwxyz{|}~ "
"ÇüéâäàåçêëèïîìÄÅÉæÆôöòûùÿÖÜ¢£¥₧ƒ"
"áíóúñѪº¿⌐¬½¼¡«»░▒▓│┤╡╢╖╕╣║╗╝╜╛┐"
"└┴┬├─┼╞╟╚╔╩╦╠═╬╧╨╤╥╙╘╒╓╫╪┘┌█▄▌▐▀"
"αßΓπΣσµτΦΘΩδ∞φε∩≡±≥≤⌠⌡÷≈°∙·√ⁿ²■ ");
The HexView widget derives from QAbstractScrollArea and visualizes a memory-mapped chunk of data:
class HexView : public QAbstractScrollArea {
Q_OBJECT
QImage const m_nullImage;
const int m_addressChars = 8;
const int m_dataMargin = 4;
const char * m_data = {};
size_t m_dataSize = 0;
size_t m_dataStart = 0;
QSize m_glyphSize;
QPointF m_glyphPos;
int m_charsPerLine, m_lines;
QMap<QChar, QImage> m_glyphs;
QFont m_font{"Monaco"};
QFontMetricsF m_fm{m_font};
struct DrawUnit { QPoint pos; const QImage *glyph; QColor fg, bg; };
QFutureSynchronizer<void> m_sync;
QVector<DrawUnit> m_chunks;
QVector<QImage> m_stores;
using chunk_it = QVector<DrawUnit>::const_iterator;
using store_it = QVector<QImage>::const_iterator;
static inline QChar decode(char ch) { return CP437[uchar(ch)]; }
inline int xStep() const { return m_glyphSize.width(); }
inline int yStep() const { return m_glyphSize.height(); }
void initData() {
int const width = viewport()->width() - m_addressChars*xStep() - m_dataMargin;
m_charsPerLine = (width > 0) ? width/xStep() : 0;
m_lines = viewport()->height()/yStep();
if (m_charsPerLine && m_lines) {
verticalScrollBar()->setRange(0, m_dataSize/m_charsPerLine);
verticalScrollBar()->setValue(m_dataStart/m_charsPerLine);
} else {
verticalScrollBar()->setRange(0, 0);
}
}
const QImage &glyph(QChar ch) {
auto &glyph = m_glyphs[ch];
if (glyph.isNull()) {
QPointF extent = m_fm.boundingRect(ch).translated(m_glyphPos).bottomRight();
glyph = QImage(m_glyphSize, QImage::Format_ARGB32_Premultiplied);
glyph.fill(Qt::transparent);
QPainter p{&glyph};
p.setPen(Qt::white);
p.setFont(m_font);
p.translate(m_glyphPos);
p.scale(std::min(1.0, (m_glyphSize.width()-1)/extent.x()),
std::min(1.0, (m_glyphSize.height()-1)/extent.y()));
p.drawText(QPointF{}, {ch});
}
return glyph;
}
The parallelized rendering is done in class methods - they don't modify the state of the widget, other than accessing read-only data, and rendering into the backing store. The threads each act on isolated lines in the store.
static void drawChar(const DrawUnit & u, QPainter &p) {
const QRect rect(u.pos, u.glyph->size());
p.setCompositionMode(QPainter::CompositionMode_Source);
p.drawImage(u.pos, *u.glyph);
p.setCompositionMode(QPainter::CompositionMode_SourceOut);
p.fillRect(rect, u.bg);
p.setCompositionMode(QPainter::CompositionMode_DestinationOver);
p.fillRect(rect, u.fg);
}
static QFuture<void> submitChunks(chunk_it begin, chunk_it end, store_it store) {
return QtConcurrent::run([begin, end, store]{
QPainter p(const_cast<QImage*>(&*store));
for (auto it = begin; it != end; it++)
drawChar(*it, p);
});
}
This method distributes the chunks of work between threads:
int processChunks() {
m_stores.resize(QThread::idealThreadCount());
BackingStoreView view(viewport());
if (!view.isAView(m_stores.last()))
std::generate(m_stores.begin(), m_stores.end(), [&view]{ return view.getView(); });
std::ptrdiff_t jobSize = std::max(128, (m_chunks.size() / m_stores.size())+1);
auto const cend = m_chunks.cend();
int refY = 0;
auto store = m_stores.cbegin();
for (auto it = m_chunks.cbegin(); it != cend;) {
auto end = it + std::min(cend-it, jobSize);
while (end != cend && (end->pos.y() == refY || (refY = end->pos.y(), false)))
end++; // break chunks across line boundaries
m_sync.addFuture(submitChunks(it, end, store));
it = end;
store++;
}
m_sync.waitForFinished();
m_sync.clearFutures();
m_chunks.clear();
return store - m_stores.cbegin();
}
The remainder of the implementation is uncontroversial:
protected:
void paintEvent(QPaintEvent *ev) override {
QElapsedTimer time;
time.start();
QPainter p{viewport()};
QPoint pos;
QPoint const step{xStep(), 0};
auto dividerX = m_addressChars*xStep() + m_dataMargin/2.;
p.drawLine(dividerX, 0, dividerX, viewport()->height());
int offset = 0;
QRect rRect = ev->rect();
p.end();
while (offset < m_charsPerLine*m_lines && m_dataStart + offset < m_dataSize) {
const auto address = QString::number(m_dataStart + offset, 16);
pos += step * (m_addressChars - address.size());
for (auto c : address) {
if (QRect(pos, m_glyphSize).intersects(rRect))
m_chunks.push_back({pos, &glyph(c), Qt::black, Qt::white});
pos += step;
}
pos += {m_dataMargin, 0};
auto bytes = std::min(m_dataSize - offset, (size_t)m_charsPerLine);
for (int n = bytes; n; n--) {
if (QRect(pos, m_glyphSize).intersects(rRect))
m_chunks.push_back({pos, &glyph(decode(m_data[m_dataStart + offset])), Qt::red, Qt::white});
pos += step;
offset ++;
}
pos = {0, pos.y() + yStep()};
}
int jobs = processChunks();
newStatus(QStringLiteral("%1ms n=%2").arg(time.nsecsElapsed()/1e6).arg(jobs));
}
void resizeEvent(QResizeEvent *) override {
initData();
}
void scrollContentsBy(int, int dy) override {
m_dataStart = verticalScrollBar()->value() * (size_t)m_charsPerLine;
viewport()->scroll(0, dy * m_glyphSize.height(), viewport()->rect());
}
public:
HexView(QWidget * parent = nullptr) : HexView(nullptr, 0, parent) {}
HexView(const char * data, size_t size, QWidget * parent = nullptr) :
QAbstractScrollArea{parent}, m_data(data), m_dataSize(size)
{
QRectF glyphRectF{0., 0., 1., 1.};
for (int i = 0x20; i < 0xE0; ++i)
glyphRectF = glyphRectF.united(m_fm.boundingRect(CP437[i]));
m_glyphPos = -glyphRectF.topLeft();
m_glyphSize = QSize(std::ceil(glyphRectF.width()), std::ceil(glyphRectF.height()));
initData();
}
void setData(const char * data, size_t size) {
if (data == m_data && size == m_dataSize) return;
m_data = data;
m_dataSize = size;
m_dataStart = 0;
initData();
viewport()->update();
}
Q_SIGNAL void newStatus(const QString &);
};
We leverage modern 64-bit systems and memory-map the source file to be visualized by the widget. For test purposes, a view of the character set is also available:
int main(int argc, char ** argv) {
QApplication app{argc, argv};
QFile file{app.applicationFilePath()};
if (!file.open(QIODevice::ReadOnly)) return 1;
auto *const map = (const char*)file.map(0, file.size(), QFile::MapPrivateOption);
if (!map) return 2;
QWidget ui;
QGridLayout layout{&ui};
HexView view;
QRadioButton exe{"Executable"};
QRadioButton charset{"Character Set"};
QLabel status;
layout.addWidget(&view, 0, 0, 1, 4);
layout.addWidget(&exe, 1, 0);
layout.addWidget(&charset, 1, 1);
layout.addWidget(&status, 1, 2, 1, 2);
QObject::connect(&exe, &QPushButton::clicked, [&]{
view.setData(map, (size_t)file.size());
});
QObject::connect(&charset, &QPushButton::clicked, [&]{
static std::array<char, 256> data;
std::iota(data.begin(), data.end(), char(0));
view.setData(data.data(), data.size());
});
QObject::connect(&view, &HexView::newStatus, &status, &QLabel::setText);
charset.click();
ui.resize(1000, 800);
ui.show();
return app.exec();
}
#include "main.moc"
One solution I sometimes use is to keep a cache of pre-rendered lines. I normally use a doubly-linked LRU list of entries with about twice the lines that can be seen on the screen. Every time a line is used for rendering is moved to the front of the list; when I need to create a new line and the current cache count is past the limit I reuse the last entry in the list.
By storing the final result of individual lines you can repaint the display very quickly as probably in many cases most of the lines will not change from one frame to the next (including when scrolling).
The increased complexity is also reasonably confined in having to invalidate the line when you change the content.

navigate between widgets using arrows in QT

I'm working on UI using QT. The ui is simple, it's app based like IPhone or Android. Say there are 9 items (3 rows x 3 cols).
What I want to do is to navigate between widgets using arrow keys.
If the focus is in [row 1,col 1] and I press down arrow, I want it to go to [row 2, col 1]
another example.
If the focus is in [row 2,col 3] and I press up arrow, I want it to go to [row 1, col 3]
But the current behavior is up and right always go to next widget and down and left always go to previous widget.
Is there any way to do this in qt? or I need to create some algorithm to do this?
Thanks
UPDATE: See amazing example at the end.
Basic Widget focus navigation starts out with this:
http://qt-project.org/doc/qt-4.8/focus.html
Arrow navigation is available easily with a QTableView:
http://qt-project.org/doc/qt-4.8/qtableview.html#navigation
If you can get your widgets to work inside the structure of a QTableView, then you don't need to implement it, it comes as a part of the wrapper/view widget.
http://qt-project.org/doc/qt-4.8/qtablewidget.html#details
http://qt-project.org/doc/qt-4.8/model-view-programming.html
Model View programming does have a learning curve, but it is worth while to learn and use.
But this is by no means the only way to accomplish this.
There are event filters, key events, focus events that can be leveraged to accomplish this feat without using a QTableView or QTableWidget. But figuring out the best way to do it without making it look messy may take some time.
http://qt-project.org/doc/qt-4.8/qcoreapplication.html#notify
http://doc.qt.digia.com/qq/qq11-events.html
http://qt-project.org/doc/qt-4.8/eventsandfilters.html
http://qt-project.org/doc/qt-4.8/qkeyevent.html#details
http://qt-project.org/doc/qt-4.8/qfocusevent.html
Key events are set to the item with the focus, and if they ignore the event it propagates up to its parent. So as long as your items in your table/grid ignore the key events having to do with the arrow keys, then you could have your parent widget listen for the key events and handle them appropriately.
http://qt-project.org/doc/qt-4.8/qt.html#Key-enum
http://qt-project.org/doc/qt-4.8/qt.html#FocusReason-enum
http://qt-project.org/doc/qt-4.8/qwidget.html#setFocus
http://qt-project.org/doc/qt-4.8/qapplication.html#focusWidget
Hope that helps.
EDIT: Fully working example in QGraphicsView of what you want to do:
Qt Creator > Welcome tab > Examples > Pad Navigator Example
http://qt-project.org/doc/qt-4.8/graphicsview-padnavigator.html
Here is the relevant code from the example:
// Enable key navigation using state transitions
for (int y = 0; y < rows; ++y) {
for (int x = 0; x < columns; ++x) {
QState *state = stateGrid[y][x];
QKeyEventTransition *rightTransition = new QKeyEventTransition(this, QEvent::KeyPress,
Qt::Key_Right, state);
QKeyEventTransition *leftTransition = new QKeyEventTransition(this, QEvent::KeyPress,
Qt::Key_Left, state);
QKeyEventTransition *downTransition = new QKeyEventTransition(this, QEvent::KeyPress,
Qt::Key_Down, state);
QKeyEventTransition *upTransition = new QKeyEventTransition(this, QEvent::KeyPress,
Qt::Key_Up, state);
rightTransition->setTargetState(stateGrid[y][(x + 1) % columns]);
leftTransition->setTargetState(stateGrid[y][((x - 1) + columns) % columns]);
downTransition->setTargetState(stateGrid[(y + 1) % rows][x]);
upTransition->setTargetState(stateGrid[((y - 1) + rows) % rows][x]);
EDIT:
Amazing example using QShortcuts and a QGridLayout and a bunch of QPushButtons:
widget.cpp
#include "widget.h"
#include <QPushButton>
#include <QApplication>
#include <QShortcut>
Widget::Widget(QWidget *parent)
: QWidget(parent)
{
m_grid = new QGridLayout;
for(int r = 0; r < 10; r++)
{
for(int c = 0; c < 10; c++)
{
m_grid->addWidget(new QPushButton("Row " + QString::number(r)
+ ", Col " + QString::number(c)),
r, c);
}
}
this->setLayout(m_grid);
m_grid->itemAtPosition(1, 1)->widget()->setFocus();
this->setStyleSheet("QPushButton::focus{ background: black; color: white;}");
// only works for in Qt for Embedded Linux, Symbian and Windows CE only.
// QApplication::setNavigationMode(Qt::NavigationModeKeypadDirectional);
QShortcut * shortcut;
shortcut = new QShortcut(QKeySequence(Qt::Key_Up),this,
SLOT(on_up()));
shortcut = new QShortcut(QKeySequence(Qt::Key_Down),this,
SLOT(on_down()));
shortcut = new QShortcut(QKeySequence(Qt::Key_Left),this,
SLOT(on_left()));
shortcut = new QShortcut(QKeySequence(Qt::Key_Right),this,
SLOT(on_right()));
}
void Widget::on_up()
{
moveFocus(0, -1);
}
void Widget::on_down()
{
moveFocus(0, 1);
}
void Widget::on_left()
{
moveFocus(-1, 0);
}
void Widget::on_right()
{
moveFocus(1, 0);
}
void Widget::moveFocus(int dx, int dy)
{
if(qApp->focusWidget() == 0)
return;
int idx = m_grid->indexOf(qApp->focusWidget());
if(idx == -1)
return;
int r, c, rowSpan, colSpan;
m_grid->getItemPosition(idx, &r, &c, &rowSpan, &colSpan);
QLayoutItem* layoutItem = m_grid->itemAtPosition(r + dy, c + dx);
if(layoutItem == 0)
return;
layoutItem->widget()->setFocus();
}
Widget::~Widget()
{
}
widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QGridLayout>
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = 0);
~Widget();
QGridLayout * m_grid;
public slots:
void on_up();
void on_down();
void on_left();
void on_right();
void moveFocus(int dx, int dy);
};
#endif // WIDGET_H
main.cpp
#include "widget.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();
return a.exec();
}
To enable keypad navigation, build Qt with QT_KEYPAD_NAVIGATION defined.
https://het.as.utexas.edu/HET/Software/html/qapplication.html#keypadNavigationEnabled

SpellChecker (speller) on webkit

I believe that there is no native functions in QtWebKit to use SpellChecker.
Is there any way to get the fields (<textarea>, <input> and <tagName contenteditable=true>) of the current page and highlight specific words (add underline only words possibly wrong)?
[edit]
I need to add "visual effect" (underline) to the Words and not the dom elements, for example if I have a html like this:
<textarea>Helllo world!</textarea>
only the word "Helllo" will be underlined, example:
Thank you.
UPDATE:
No, as far as I can tell from poking and prodding at QtWebKit, you can't format the contents of a textarea.
Format text in a <textarea>?
You could maybe replace it with a div that looks and acts like a textarea, and then insert some tags around specific words.
But near as I can tell from working on this question, it isn't possible with QWebElement.
You could go and ask the trolls and see if they have any suggestions.
Here is the code that got the closest. When the webpage comes up, right click on different places on the page.
main.cpp
#include <QApplication>
#include "webview.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
WebView w;
w.show();
return a.exec();
}
webview.h
#ifndef WEBVIEW_H
#define WEBVIEW_H
#include <QWebView>
#include <QContextMenuEvent>
class WebView : public QWebView
{
Q_OBJECT
public:
explicit WebView(QWidget *parent = 0);
~WebView();
public slots:
void contextMenuEvent(QContextMenuEvent *);
private:
};
#endif // WEBVIEW_H
webview.cpp
#include "webview.h"
#include <QWebFrame>
#include <QWebElement>
#include <QWebElementCollection>
#include <QDebug>
WebView::WebView(QWidget *parent) :
QWebView(parent)
{
this->setUrl(QUrl("http://www.w3schools.com/tags/tag_textarea.asp"));
// right click on different parts of the web page
}
WebView::~WebView(){ }
void WebView::contextMenuEvent(QContextMenuEvent * cme)
{
QPoint pos = cme->pos();
QWebHitTestResult whtr = this->page()->frameAt(pos)->hitTestContent(pos);
QWebElement we = whtr.element();
if(we.isNull())
{
qDebug() << "WebElement is null.";
}
else
{
qDebug() << we.tagName() << "OuterXML <<<<<" << we.toOuterXml() << ">>>>>";
qDebug() << we.tagName() << "InnerXML <<<<<" << we.toInnerXml() << ">>>>>";
qDebug() << we.tagName() << "PlainText <<<<<" << we.toPlainText() << ">>>>>";
// TODO: replace the lines below with a better way of extracting words from the DOM and the HTML tags
// This current method modifies tags instead of just the text inside tags.
QStringList list = we.toPlainText().split(' ');
for(int i = 0; i < list.size(); i++)
{
// TODO: Insert dictionary logic here when examining words
if(list.at(i).size() > 5)
{
list[i] = "<span class=\"sp\" style=\"border-bottom: 1px dotted red;\">" + list.at(i) + "</span>";
}
}
qDebug() << list.join(" ");
we.setInnerXml(list.join(" "));
qDebug() << "-------------------------------------------";
}
}
So after some additional research (after some changes to your question) here is the method I would look into:
When a right click is performed on the page, the QWidget (your QWebView) sends out a QContextMenuEvent.
http://qt-project.org/doc/qt-4.8/qcontextmenuevent.html#details
Get the position out of that event, and then drill down into your web page to find out what it was for:
Get the web frame at the click location...
QWebFrame * QWebPage::frameAt ( const QPoint & pos ) const
Do a hit test content at the location...
QWebHitTestResult QWebFrame::hitTestContent ( const QPoint & pos ) const
Query the element out of the hit test...
QWebElement QWebHitTestResult::element () const
Double check that the content is editable by the user...
bool QWebHitTestResult::isContentEditable () const
But that is about as far as I have gotten on this research project.
If you restyle the webelements on the page to have a span tag of your misspelled class, then you could look for those and then either create your own popup menu, or edit the contextMenu of the QWebView right then.
So, no, there is not a context menu for elements on the page, but you can simulate it, if you find the element that is clicked on, and then change the contextMenu for the QWidget.
http://qt-project.org/doc/qt-4.8/webkit-simpleselector.html
void Window::on_elementLineEdit_returnPressed()
{
QWebFrame *frame = webView->page()->mainFrame();
QWebElement document = frame->documentElement();
QWebElementCollection elements = document.findAll(elementLineEdit->text());
foreach (QWebElement element, elements)
element.setAttribute("style", "background-color: #f0f090");
}
http://qt-project.org/doc/qt-4.8/mainwindows-menus.html
void MainWindow::contextMenuEvent(QContextMenuEvent *event)
{
QMenu menu(this);
menu.addAction(cutAct);
menu.addAction(copyAct);
menu.addAction(pasteAct);
menu.exec(event->globalPos());
}
Again, I hope that helps.
As far as awesome examples of using QWebKit, there is this project:
How to create Web History for my Browser
https://code.google.com/p/arora/
I did a search on the repo for "spell" and "spellcheck" and nothing useful came up.
As far as tweaking the html on the fly, the Fancy Browser example shows how it's done:
http://qt-project.org/doc/qt-4.8/webkit-fancybrowser-mainwindow-cpp.html
void MainWindow::rotateImages(bool invert)
{
QString code;
if (invert)
code = "$('img').each( function () { $(this).css('-webkit-transition', '-webkit-transform 2s'); $(this).css('-webkit-transform', 'rotate(180deg)') } )";
else
code = "$('img').each( function () { $(this).css('-webkit-transition', '-webkit-transform 2s'); $(this).css('-webkit-transform', 'rotate(0deg)') } )";
view->page()->mainFrame()->evaluateJavaScript(code);
}
They just use jquery and run additional javascript on a loaded page.
So you could probably substitute "$('img').each( for "$('textarea').each( and act on the text of an area.
You could also run a regex on the page or use an html parser to find all the <textarea> blocks.
Hope that helps.

connecting a signal of widget in a plasmoid

I am new to Qt and am trying to connect the cilicked signal o a push button with a function hile writing a plasmoid. I am trying to use an external function as a public with Plasma::PushButton type object so that I can use it to connect it with the clicked signal? With gtk it was as simple as on_...._clicked do this but isnt there a simple way in qt, where we can do away with the need to use slots?
#include "plasma-tutorial1.h"
#include<string.h>
#include <stdlib.h>
#include <QGraphicsLinearLayout>
#include <QPainter>
#include <QFontMetrics>
#include <QSizeF>
#include <QTextEdit>
#include <plasma/svg.h>
#include <plasma/theme.h>
#include <plasma/widgets/lineedit.h>
#include <plasma/widgets/pushbutton.h>
#include <plasma/widgets/textedit.h>
//PlasmaTutorial1 mainf;
themainfunction(int choice,Plasma::LineEdit *m_lineEdit,
Plasma::TextEdit *m_displaytext)
{
char buffer[100];
const char *inp=(const char *)malloc(sizeof(char)*100);
QString input;
input=m_lineEdit->text();
QByteArray byteArray = input.toUtf8();
inp = byteArray.constData();
char *expression;
expression=(char *)malloc(sizeof(char)*100);
strcpy(expression,"sudo apt-");
switch(choice)
{
case 1:{
strcat(expression,"get install ");
strcat(expression,inp);
break;
};
case 2:{
strcat(expression,"get remove ");
strcat(expression,inp);
break;
};
case 3:{
strcat(expression,"cache search ");
strcat(expression,inp);
break;
};
};
/*
FILE* in;
FILE* ptr=fopen("new.txt","w");
FILE *popen();
if(!(in = popen("cal","r")))
{return;}
while(fgets(buffer, 100, in) != NULL) {
*/
m_displaytext->append("yeah!");
// fprintf(ptr,"%s",buffer);
//}
//pclose(in);
//fclose(ptr);
}
PlasmaTutorial1::PlasmaTutorial1(QObject *parent, const QVariantList &args)
: Plasma::Applet(parent, args),
m_svg(this),
m_icon("document")
{
m_svg.setImagePath("widgets/background");
// this will get us the standard applet background, for free!
setBackgroundHints(DefaultBackground);
resize(200, 200);
}
PlasmaTutorial1::~PlasmaTutorial1()
{
if (hasFailedToLaunch()) {
// Do some cleanup here
} else {
// Save settings
}
}
void PlasmaTutorial1::init()
{
/* // A small demonstration of the setFailedToLaunch function
if (m_icon.isNull()) {
setFailedToLaunch(true, "No world to say hello");
}*/
Counter rt;
QGraphicsLinearLayout *layout = new QGraphicsLinearLayout(this);
layout->setOrientation(Qt::Vertical); //so widgets will be stacked up/down
m_lineEdit = new Plasma::LineEdit(this);
m_lineEdit->setText("Enter the package name here");
m_displaytext = new Plasma::TextEdit(this);
m_displaytext->setText("Terminal");
m_installButton = new Plasma::PushButton(this);
m_installButton->setText("Install");
connect(m_installButton, SIGNAL(clicked()),&rt,SLOT(themainfunction(1,m_lineEdit,m_displaytext)));
m_removeButton = new Plasma::PushButton(this);
m_removeButton->setText("Remove");
// m_removeButton->clicked()
connect(m_removeButton, SIGNAL(clicked()),&rt,SLOT(themainfunction(2,m_lineEdit,m_displaytext)));
m_searchButton = new Plasma::PushButton(this);
m_searchButton->setText("Search");
connect(m_searchButton, SIGNAL(clicked()),&rt,SLOT(themainfunction(3,m_lineEdit,m_displaytext)));
layout->addItem(m_lineEdit);
layout->addItem(m_installButton);
layout->addItem(m_removeButton);
layout->addItem(m_searchButton);
layout->addItem(m_displaytext);
m_displaytext->append("yo baby!");
}
/*
void PlasmaTutorial1::paintInterface(QPainter *p,
const QStyleOptionGraphicsItem *option, const QRect &contentsRect)
{
p->setRenderHint(QPainter::SmoothPixmapTransform);
p->setRenderHint(QPainter::Antialiasing);
// Now we draw the applet, starting with our svg
m_svg.resize((int)contentsRect.width(), (int)contentsRect.height());
m_svg.paint(p, (int)contentsRect.left(), (int)contentsRect.top());
// We place the icon and text
p->drawPixmap(7, 0, m_icon.pixmap((int)contentsRect.width(),(int)contentsRect.width()-14));
p->save();
p->setPen(Qt::white);
p->drawText(contentsRect,
Qt::AlignBottom | Qt::AlignHCenter,
"Hello Plasmoid!");
p->restore();
}
*/
// This is the command that links your applet to the .desktop file
K_EXPORT_PLASMA_APPLET(tutorial1, PlasmaTutorial1)
#include "plasma-tutorial1.moc"
say i want to connect themainfunction() upon clicked signal of install button . how do i do it? how can I derive a class in plasma?
i got where was i missing out. We cannot pass objects as arguments in slot functions. Now it is running smooth. thanx for all your replies.

Transparent Qt-widget and Ogre

we ’ve been looking into using transparent widgets as overlays for ogre. Although Qwidgets are transparent by default, overlaying them over an Ogre widget is different and a black screen arises. On the ogre forum (http://www.ogre3d.org/forums/viewtopic.php?f=2&t=42733) I found the following:
"Ok, to get my ideas straight I’m going to summarise the various approaches I have found to combining Ogre and Qt:
Create a window (not necessarily a QGLWidget) using Qt and pass its window handle to Ogre using the ‘externalWindowHandle’ flag. Ogre then creates a context and is fully responsible for it. This is basically what I did for the first demo I made. It has the advantage that it should support both OpenGL and Direct3D, and also should work accross all platforms. The big drawback is that Qt widgets can only be overlaid (not integrated)
so you don’t get the nice transparency.
An approach similar to (1) but with the difference that the frame buffer is explicitly read back from Ogre and used as a widget background. This would again work accross all render systems and platforms, and now Qt can perform proper compositing from transparency. However, it is potenially slow doe to the need to read back every frame and copy it to Qt. But this could make a good ‘fallback’ approach. I haven’t tried implementing it yet.
This is the ‘proper’ approach which we are really considering in this thread. It involves both Ogre and Qt owning OpenGL contexts and both rendering into the same widget. This widget is set as the background of a QGraphicsView/QGraphicsScene and other widgets can be overliad with proper transpaency effects. It only works with OpenGL and is (theorectically) cross platform. There are two variations:
Allow Ogre to create it’s own OpenGL context (passing the flag ‘externalGLControl’) and then retieve the context once createRenderWindow() has finished. Under windows there are the wglGetCurrentDC() and wglGetCurrentContext() for this – other platforms should have something similar.
Have Qt create a context on Ogre’s behalf and pass that to Ogre using the ‘externalGLContext’ flag. In this case Ogre basically does nothing except render into the context it it provided with – all the control is with Qt. I haven’t quite got this to work yet as I was having crashes in both Qt and Ogre."
Approach 1 is the one we followed for a project and as said above we’ve encountered the same problem with transparency. Approach 3 is possible, but we would be limiting ourselves to openGL. The code for that is available one page 3 of the forum-link.
We’ve also found a demo video but I can’t find how it was implemented, but it looks really cool: http://youtu.be/b_3xfFuwGOQ
You can now find an implementation of the second variant of your third proposed approach in an updated QmlOgre example at https://github.com/advancingu/QmlOgre The original example had a few issues that were fixed here.
Hope this still helps a few months after your question.
I couldn't find sample implementations of options 2 and 3, so I'll share mine here.
I've tested the implementations below with Qt 5.4.0 x86 and OGRE 1.10.0 x86 on Windows 10.
Disclaimer: This is sample code. I'm not recommending you to:
implement everything in header files;
use owning raw pointers - use smart pointers, instead.
Direct OpenGL backend
A possible implementation of option 3.2 is the following:
// OgreGLWidget.h
#pragma once
#include "Scene.h"
#include "OgreSceneManager.h"
#include "OgreRenderSystem.h"
#include "OgreRenderWindow.h"
#include "OgreRoot.h"
#include <QtWidgets/QOpenGLWidget>
#include <algorithm>
#include <cstdint>
class OgreGLWidget final
: public QOpenGLWidget
{
Q_OBJECT
public:
explicit OgreGLWidget(QWidget* parent = nullptr)
:
QOpenGLWidget(parent),
Root_("plugins" OGRE_BUILD_SUFFIX ".cfg", "ogre.cfg")
{ }
~OgreGLWidget() override
{
this->Scene_.clear();
if (this->SceneManager_)
this->Root_.destroySceneManager(this->SceneManager_);
if (this->RenderWindow_)
this->RenderWindow_->destroy();
}
protected:
void initializeGL() override
{
QOpenGLWidget::initializeGL();
if (auto* glRenderSystem = this->getGlRenderSystem())
{
this->Root_.setRenderSystem(glRenderSystem);
auto* renderWindow = this->Root_.initialise(false);
assert(renderWindow == nullptr && "The render window must be created afterwards");
}
else
{
throw std::runtime_error("Cannot find GL render system");
}
Ogre::NameValuePairList params;
params["externalGLControl"] = "true";
params["hidden"] = "true";
// Pass the current OpenGL context to OGRE
// - either like this
params["currentGLContext"] = "true";
// - or like this
//if (auto const* openGLContext = QOpenGLContext::currentContext())
//{
// auto const nativeHandle = openGLContext->nativeHandle();
// if (!nativeHandle.isNull() && nativeHandle.canConvert<QWGLNativeContext>())
// {
// auto nativeContext = nativeHandle.value<QWGLNativeContext>();
// auto nativeRenderingContextHandle = nativeContext.context();
// params["externalGLContext"] = Ogre::StringConverter::toString(reinterpret_cast<unsigned long>(nativeRenderingContextHandle));
// qDebug("OpenGLContext: nativeHandle=%p, windowHandle=%p", nativeRenderingContextHandle, nativeContext.window());
// }
//}
// Setup scene
this->RenderWindow_ = this->Root_.createRenderWindow("", this->width(), this->height(), false, &params);
this->SceneManager_ = this->Root_.createSceneManager(Ogre::SceneType::ST_GENERIC);
this->SceneManager_->setAmbientLight(Ogre::ColourValue::White);
this->Scene_ = Scene(*this->SceneManager_, *this->RenderWindow_);
}
void paintGL() override
{
QOpenGLWidget::paintGL();
this->Root_.renderOneFrame();
// Queue another update to call paintGL again.
// Not ideal as it will render even if the scene hasn't changed.
this->update();
}
void resizeGL(int width, int height) override
{
QOpenGLWidget::resizeGL(width, height);
this->RenderWindow_->resize(width, height);
}
private:
Ogre::Root Root_;
Ogre::RenderWindow* RenderWindow_{ nullptr };
Ogre::SceneManager* SceneManager_{ nullptr };
Scene Scene_{};
Ogre::RenderSystem* getGlRenderSystem()
{
static Ogre::String const render_system_name{ "OpenGL Rendering Subsystem" };
auto const& renderSystems = this->Root_.getAvailableRenderers();
auto const lastRenderSystem = std::cend(renderSystems);
auto const glRenderSystemIt = std::find_if(std::cbegin(renderSystems), lastRenderSystem,
[](Ogre::RenderSystem const* renderSystem) { return renderSystem->getName() == render_system_name; });
return (glRenderSystemIt == lastRenderSystem) ? nullptr : *glRenderSystemIt;
}
};
Here you are a screenshot of the application running:
Buffered D3D9/OpenGL backend
A possible implementation of option 2 is the following:
// OgreWidget.h
#pragma once
#include "Scene.h"
#include "OgreRoot.h"
#include "OgreRenderWindow.h"
#include "OgreSceneManager.h"
#include <QtGui/qevent.h>
#include <QtGui/QPainter>
#include <QtWidgets/QWidget>
#include <cstdint>
class OgreWidget final
: public QWidget
{
Q_OBJECT
public:
explicit OgreWidget(QWidget *parent = nullptr)
:
QWidget(parent),
Root_("plugins" OGRE_BUILD_SUFFIX ".cfg", "ogre.cfg")
{
//static Ogre::String const render_system_name{ "OpenGL Rendering Subsystem" };
static Ogre::String const render_system_name{ "Direct3D9 Rendering Subsystem" };
if (auto* renderSystem = this->getRenderSystem(render_system_name))
{
this->Root_.setRenderSystem(renderSystem);
auto* renderWindow = this->Root_.initialise(false);
assert(renderWindow == nullptr && "The render window must be created afterwards");
}
else
{
throw std::runtime_error("Cannot find render system: " + render_system_name);
}
Ogre::NameValuePairList params;
params["hidden"] = "true";
this->RenderWindow_ = this->Root_.createRenderWindow("", this->width(), this->height(), false, &params);
this->SceneManager_ = this->Root_.createSceneManager(Ogre::SceneType::ST_GENERIC);
this->SceneManager_->setAmbientLight(Ogre::ColourValue::White);
this->Scene_ = Scene(*this->SceneManager_, *this->RenderWindow_);
}
~OgreWidget() override
{
this->Scene_.clear();
if (this->SceneManager_)
this->Root_.destroySceneManager(this->SceneManager_);
if (this->RenderWindow_)
this->RenderWindow_->destroy();
}
protected:
void paintEvent(QPaintEvent* evt) override
{
this->Root_.renderOneFrame();
this->RenderWindow_->update();
{
static auto const memory_category = Ogre::MemoryCategory::MEMCATEGORY_RENDERSYS;
static auto const pixel_format = Ogre::PixelFormat::PF_A8R8G8B8;
auto const width = this->RenderWindow_->getWidth();
auto const height = this->RenderWindow_->getHeight();
auto const bytesPerPixel = Ogre::PixelUtil::getNumElemBytes(pixel_format);
auto const byteCount = width * height * bytesPerPixel;
auto* data = OGRE_ALLOC_T(std::uint8_t, byteCount, memory_category);
Ogre::PixelBox pixelBox(width, height, 1, pixel_format, data);
this->RenderWindow_->copyContentsToMemory(pixelBox, pixelBox);
static auto const image_format = QImage::Format::Format_ARGB32;
QImage const background(data, width, height, image_format);
QPainter painter(this);
painter.drawImage(QPointF{ 0., 0. }, background, background.rect(), Qt::ImageConversionFlag::NoFormatConversion);
OGRE_FREE(data, memory_category);
}
QWidget::paintEvent(evt);
// Queue another update to call paintEvent again.
// Not ideal as it will render even if the scene hasn't changed.
this->update();
}
void resizeEvent(QResizeEvent* evt) override
{
auto const& size = evt->size();
auto const width = size.width();
auto const height = size.height();
this->RenderWindow_->resize(width, height);
QWidget::resizeEvent(evt);
}
private:
Ogre::Root Root_;
Ogre::RenderWindow* RenderWindow_{ nullptr };
Ogre::SceneManager* SceneManager_{ nullptr };
Scene Scene_;
Ogre::RenderSystem* getRenderSystem(Ogre::String const& renderSystemName)
{
auto const& renderSystems = this->Root_.getAvailableRenderers();
auto const lastRenderSystem = std::cend(renderSystems);
auto const renderSystemIt = std::find_if(std::cbegin(renderSystems), lastRenderSystem,
[&](Ogre::RenderSystem const* renderSystem) { return renderSystem->getName() == renderSystemName; });
return (renderSystemIt == lastRenderSystem) ? nullptr : *renderSystemIt;
}
};
Here you are a screenshot of the application running:
Performance
This approach is considerably slower than the OpenGL one.
On my machine, when the application is maximized, a frame is rendered in about:
~14ms with the (buffered) OpenGL backend;
~11ms with the (buffered) D3D9 backend;
~2 ms with the OpenGL backend;
Issues
For some reason, when using the buffered OpenGL backend, the cube has a different color:
I've not bothered to investigate it: if OpenGL is available, you most probably want to render the scene with class OgreGLWidget.
Boilerplate code
I'm embedding the OGRE scene as a child widget of centralWidget in my MainWindow instance:
// MainWindow.h
#pragma once
#include "OgreGLWidget.h"
#include "OgreWidget.h"
#include <QtWidgets/QLabel>
#include <QtWidgets/QLayout>
#include <QtWidgets/QMainWindow>
#include <QtWidgets/QPushButton>
#include "ui_MainWindow.h"
class MainWindow final
: public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget* parent = nullptr)
: QMainWindow(parent)
{
this->Ui_.setupUi(this);
auto* gridLayout = new QGridLayout(this->Ui_.centralWidget);
gridLayout->setSpacing(6);
gridLayout->setContentsMargins(0, 0, 0, 0);
// Uncomment based on whether you want to use OpenGL or D3D9 as backend.
this->OgreWidget_ = new OgreGLWidget(this->Ui_.centralWidget);
//this->OgreWidget_ = new OgreWidget(this->Ui_.centralWidget);
gridLayout->addWidget(this->OgreWidget_);
// Show an overlay widget when "Show Widget" is pressed.
auto* action = new QAction("Show Widget", this);
QObject::connect(action, &QAction::triggered, this, &MainWindow::showWidgetSlot);
this->Ui_.mainToolBar->addAction(action);
}
~MainWindow() override = default;
private slots:
void showWidgetSlot()
{
auto* w = new QWidget(this->OgreWidget_);
w->setAttribute(Qt::WidgetAttribute::WA_DeleteOnClose);
w->setAttribute(Qt::WidgetAttribute::WA_NoMousePropagation);
w->setStyleSheet(".QWidget { background-color: rgba(255,255,255,75%); border-radius: 10px; }");
auto layout = new QVBoxLayout(w);
layout->addWidget(new QLabel(this->tr("Hello OGRE"), w));
auto* b = new QPushButton(this->tr("Ok"), w);
layout->addWidget(b);
QObject::connect(b, &QPushButton::clicked, w, &QWidget::close);
w->resize(100, 100);
w->show();
}
private:
Ui::MainWindowClass Ui_;
QWidget* OgreWidget_{ nullptr };
};
Class Scene, responsible for setting up my scene, is implemented like this:
// Scene.h
#pragma once
#include "OgreCamera.h"
#include "OgreEntity.h"
#include "OgreMaterialManager.h"
#include "OgrePass.h"
#include "OgreRenderTarget.h"
#include "OgreSceneManager.h"
#include "OgreSceneNode.h"
#include "OgreTechnique.h"
#include "OgreViewport.h"
struct Scene
{
explicit Scene() = default;
explicit Scene(Ogre::SceneManager& sceneManager_, Ogre::RenderTarget& renderTarget_)
: sceneManager(&sceneManager_)
{
auto cubeMaterial = Ogre::MaterialManager::getSingleton().create("cubeMaterial", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
if (auto* technique = cubeMaterial->getTechnique(0))
{
if (auto* pass = technique->getPass(0))
{
pass->setLightingEnabled(true);
pass->setAmbient(Ogre::ColourValue{ 0.3f, 0.1f, 0.1f, 1 });
}
}
this->entity = sceneManager_.createEntity(Ogre::SceneManager::PrefabType::PT_CUBE);
this->entity->setMaterial(cubeMaterial);
sceneManager_.getRootSceneNode()->attachObject(this->entity);
this->camera = sceneManager_.createCamera("camera");
this->camera->setPosition(-100, 100, 300);
this->camera->lookAt(0, 0, 0);
this->camera->setNearClipDistance(5);
this->light = sceneManager_.createLight("light");
this->light->setType(Ogre::Light::LightTypes::LT_DIRECTIONAL);
this->light->setDirection(0.25, -1, -0.5);
this->viewport = renderTarget_.addViewport(this->camera);
this->viewport->setBackgroundColour(Ogre::ColourValue::Blue);
}
Scene(Scene const&) = delete;
Scene(Scene&& other)
{
this->swap(other);
}
Scene& operator=(Scene const&) = delete;
Scene& operator=(Scene&& other)
{
this->swap(other);
return *this;
}
void swap(Scene& other)
{
using std::swap;
swap(this->sceneManager, other.sceneManager);
swap(this->viewport, other.viewport);
swap(this->entity, other.entity);
swap(this->camera, other.camera);
swap(this->light, other.light);
}
void clear()
{
if (this->light)
{
this->sceneManager->destroyLight(this->light);
this->light = nullptr;
}
if (this->camera)
{
this->sceneManager->destroyCamera(this->camera);
this->camera = nullptr;
}
if (this->entity)
{
this->sceneManager->destroyEntity(this->entity);
this->entity = nullptr;
}
this->sceneManager = nullptr;
}
~Scene()
{
this->clear();
}
// -- Non-owning
Ogre::SceneManager* sceneManager{ nullptr };
Ogre::Viewport* viewport{ nullptr };
// -- Owning
Ogre::Entity* entity{ nullptr };
Ogre::Camera* camera{ nullptr };
Ogre::Light* light{ nullptr };
};
*Here is the code for that video (http://youtu.be/b_3xfFuwGOQ). (Needs Qt5)
http://qt.gitorious.org/qt-labs/qmlogre
There is also Cutexture (Needs Qt4)
https://github.com/advancingu/Cutexture
http://i56.tinypic.com/b6xb83.jpg
Here is a Qt4 Ogre Widget example. (Needs Qt4)
http://zester.googlecode.com/files/QtCreatorOgre2.zip*

Resources