Save a single character - qt

everyone.
I've created a simple textedit application.
I would like to take the single character whenever the user writes it using the keyboard.
I've thought to solve the problem in the following way:
void MainWindow::on_textEdit_textChanged()
{
QString str= ui->textEdit->toPlainText();
if (str.size()==0){
pos=0;
} else {
if(pos<str.size()) {
QChar char_prel=str.at(pos);
pos++;
chars.push_back(char_prel);
} else {
pos=0;
QString str=ui->textEdit->toPlainText();
chars.clear();
for(int i = 0; i < str.length(); i++) {
QChar char_prel=str.at(i);
chars.push_back(char_prel);
pos++;
}
}
}
}
The solution doesn't work because everytime, i read the entire string on the edit block using:
QString str= ui->textEdit->toPlainText();
and from that string i take the last inserted character.
I want to do the same thing without using the toPlaintText().
Thanks for answering

If you handle the KeyPressEvent of the QTextEdit, you'll have a parameter of QKeyEvent* type, let's call this one "e".
Then you can use "e->text()" to get the corresponding character.

Related

How to implement clipboard actions for custom mime-types?

I am trying to implement copy/cut/paste in a complex application.
I have a QGraphicsScene that can contain QGraphicsItem subtypes of varied subtypes, fairly complex (with Item as a second parent storing custom properties).
I would copy/cut selected items, and paste them back in place.
I already have implemented it using a local version: a list of items.
void copyItemsActionOld()
{
foreach(QGraphicsItem* qItem, selectedItems())
{
Item* newItem = (dynamic_cast<Item*>(qItem))->createItemCopy();
m_itemClipboard.append(newItem);
}
}
On paste, I make a copy of all items in clipboard and add them to the scene. So simple.....
BUT
I need to implement it using the global system clipboard.
I saw that creating a custom mime type is as simple as calling setData on a QMimeData object, after I make up a format name... (I hope that is true)
static const QString _mimeType("application/myItem");
void copyItemsAction()
{
QMimeData* _mimeData = new QMimeData;
2 QByteArray _itemData = ?????;
_mimeData->setData(_mimeType, _itemData);
QClipboard* _clipboard = QApplication::clipboard();
_clipboard->clear();
_clipboard->setMimeData(_mimeData);
}
void pasteItemsAction()
{
QClipboard* _clipboard = QApplication::clipboard();
const QMimeData* _mimeData = _clipboard->mimeData();
QStringList _formats = _mimeData->formats();
foreach (QString _format, _formats)
{
if (_format == _mimeType)
{
QByteArray _itemData = _mimeData->data(_mimeType);
3 // then do what ? How do I parse it ?
}
}
}
My questions
1) Are the above fragments for copyItemsAction and pasteItemsAction anywhere close to how clipboard actions should work ?
2) How can I put item data in the QByteArray ?
3) How do I parse the data in QByteArray ?
4) Do I need to register the custom mime-type anywhere else ? (other than what I just did in my two functions); and will it be multi-platform ?
I have already implemented save and load functionality for all items. Something like...
void Item::saveItem(QDataStream &outFile)
{
outFile << type;
outFile << width;
outFile << color.name();
}
Can I use this to place the items data in the QByteArray ? (How ?)
I was on the right track, and I kept adding code to my question until I found how to make it work:
static const QString _mimeType("application/myItem");
void copyItemsAction()
{
QByteArray _itemData;
QDataStream outData(&_itemData, QIODevice::WriteOnly);
outData << selectedItems().size();
foreach(QGraphicsItem* qItem, selectedItems())
{
Item* item = dynamic_cast<Item*>(qItem);
item->saveItem(outData);
}
QMimeData* _mimeData = new QMimeData;
_mimeData->setData(_mimeType, _itemData);
_mimeData->setText("My Items");
QClipboard* _clipboard = QApplication::clipboard();
_clipboard->clear();
_clipboard->setMimeData(_mimeData);
}
void pasteItemsAction()
{
QClipboard* _clipboard = QApplication::clipboard();
const QMimeData* _mimeData = _clipboard->mimeData();
QStringList _formats = _mimeData->formats();
foreach (QString _format, _formats)
{
if (_format == _mimeType)
{
QByteArray _itemData = _mimeData->data(_mimeType);
QDataStream inData(&_itemData, QIODevice::ReadOnly);
int itemsSize;
inData >> itemsSize;
for (int i = 0; i < itemsSize; ++i)
{
Item* item = ...
item->loadItem(inData);
}
}
}
}
So, for question 1, yes I was on the right track;
For questions 2 and 3 - I was able to use a QDataStream to serialize info to/from the QByteArray.
If there is a better / more effective / faster way, I would love to know...
For question 4 - it seems that I can use just about any string, if all I want is to copy/paste within a single instance of my application.
It is also true if I want to use it between multiple applications, multiple instances of my application, or for drag-and-drop - on most platforms. (It does not seem to work between multiple applications/instances in the embedded platform I target.)
Caveat - it fails frequently when another clipboard using application is open, in windows.

How to bind an argument with a dual function?

Consider these C functions:
#define INDICATE_SPECIAL_CASE -1
void prepare (long *length_or_indicator);
void execute ();
The prepare function is used to store a pointer to a delayed long * output variable.
It can be used in C like this:
int main (void) {
long length_or_indicator;
prepare (&length_or_indicator);
execute ();
if (length_or_indicator == INDICATE_SPECIAL_CASE) {
// do something to handle special case
}
else {
long length = lengh_or_indicator;
// do something to handle the normal case which has a length
}
}
I am trying to achieve something like this in Vala:
int main (void) {
long length;
long indicator;
prepare (out length, out indicator);
execute ();
if (indicator == INDICATE_SPECIAL_CASE) {
// do something to handle special case
}
else {
// do something to handle the normal case which has a length
}
}
How to write the binding for prepare () and INDICATE_SPECIAL_CASE in Vala?
Is it possible to split the variable into two?
Is it possible to avoid using pointers even though the out variable is written to after the call to prepare () (in execute ())?
The problem with using out is that Vala is going to generate lots of temporary variables along the way, which will make the reference wrong. What you probably want to do is create a method in your VAPI that hides all this:
[CCode(cname = "prepare")]
private void _prepare (long *length_or_indicator);
[CCode(cname = "execute")]
private void _execute ();
[CCode(cname = "prepare_and_exec")]
public bool execute(out long length) {
long length_or_indicator = 0;
prepare (&length_or_indicator);
execute ();
if (length_or_indicator == INDICATE_SPECIAL_CASE) {
length = 0;
return false;
} else {
length = lengh_or_indicator;
return true;
}
}

QlineEdit with some default text for which cursor should not be moved?

In QT, a created lineEdit shows a text using the setText() method.
But the cursor is movable for the default text. I want the cursor should not be movable for the default text.
My lineEdit type has been set as password. Hence the default text('Password') is also displayed as '********'. Whenever user types the type has to be changed as password and when there is no text or until the user have not typed any text, the lineEdit should display the plain text 'password'
Any idea to fix the above two issues?
In the constructor put
ui->lineEdit->setPlaceholderText("password");
ui->lineEdit->setReadOnly(1);
And in on_lineEdit_selectionChanged() SLOT, put
ui->lineEdit->setText("");
ui->lineEdit->setEchoMode(QLineEdit::Password);
ui->lineEdit->setReadOnly(0);
I noticed this question has tag pyqt so I'll put an actual answer related to that tag for those actually looking for a python way instead of c++.
self.searchEditText = QtGui.QLineEdit()
self.searchEditText.setPlaceholderText("Search for word")
I managed to do what you want by deriving a class from QLineEdit as per following..
Constructor..
QCustomLineEdit::QCustomLineEdit(QWidget *parent) :
QLineEdit(parent)
{
connect(this, SIGNAL(textChanged(QString)), this, SLOT(onTextChanged(QString)));
connect(this, SIGNAL(cursorPositionChanged(int,int)), this, SLOT(onCursorPositionChanged(int,int)));
setEchoMode(QLineEdit::Password); // Echo mode in your case..
m_echoMode = echoMode(); // Member variable to store original echo mode..
m_placeHolderText = "Password"; // Member variable..
m_isPlaceHolderActive = true; // Member varible..
// Default case..
setPlaceholderText("");
setStyleSheet("QCustomLineEdit{color: gray;}");
setEchoMode(QLineEdit::Normal);
setText(__placeHolderText);
}
Override keyPressEvent..
void QCustomLineEdit::keyPressEvent(QKeyEvent *e)
{
if(m_isPlaceHolderActive)
{
if(e->key() == Qt::Key_Delete || e->key() == Qt::Key_Backspace)
e->accept();
else
QLineEdit::keyPressEvent(e);
return;
}
QLineEdit::keyPressEvent(e);
}
Cursor position change event..
void QCustomLineEdit::onCursorPositionChanged(int /*oldPos*/, int newPos)
{
if(m_isPlaceHolderActive)
{
if(newPos != 0)
setCursorPosition(0);
}
}
Text change event..
void QCustomLineEdit::onTextChanged(const QString &text)
{
if(m_isPlaceHolderActive)
{
if(text.compare(m_placeHolderText) != 0)
{
m_isPlaceHolderActive = false;
// Remove the 'placeHolderText' from 'text' itself..
QString temp = text;
temp = temp.mid(0, text.lastIndexOf(m_placeHolderText));
setStyleSheet("QCustomLineEdit{color: black;}");
setEchoMode(m_echoMode);
setText(temp);
}
else
{
setEchoMode(QLineEdit::Normal);
setText(m_placeHolderText);
setStyleSheet("QCustomLineEdit{color: gray;}");
setCursorPosition(0);
}
}
else
{
if(text.isEmpty())
{
m_isPlaceHolderActive = true;
setStyleSheet("QCustomLineEdit{color: gray;}");
setEchoMode(QLineEdit::Normal);
setText(m_placeHolderText);
}
}
}
I have written it very hastily to just show you. Test it yourself and feel free to point any mistake(s) or optimization(s). Hope this helps.
For question 1, in Qt 5.0 and higher, setPlaceholderText does what you want. https://codereview.qt-project.org/#change,45326

QAbstactTableModel insert at top

I have addFile function in my TableModel class which inserts a new record at the end.
void TableModel::addFile(const QString &path)
{
beginInsertRows(QModelIndex(), list.size(),list.size());
TableItem item;
item.filename = path;
QFile file(path);
item.size = file.size();
item.status = StatusNew;
list << item;
endInsertRows();
}
This function works fine but instead of appending record at the end I would like to insert it at the top. Any pointers on how to update my existing function ?
I have already tried some combinations but there is no Luck.
There are two things that you need to do. First is to adjust the call to beginInsertRows. Because it is here that we are telling the model that we are adding rows, where they will go, and how many we are adding. Here is the method description:
void QAbstractItemModel::beginInsertRows ( const QModelIndex & parent,
int first, int last )
So in your case since you want to add a row at the first index, and only one row, we pass 0 as the index of the first item, and 0 which is the index of the last item we are adding (because of course we are only adding one item).
beginInsertRows(modelIndex(), 0, 0);
Next we have to provide the data for the item. I assume that 'list' is a QList (if not it is probably similar). So we want to call the 'insert' method.
list.insert(0, item);
And that should be it.
For display you can try delegates as explained in the link (I haven't tried the example though). It will help the community if you can add your observations.
Thanks to everyone for replying. I have found the solution by my own:
In case if anyone is interested
void TableModel::addFile(const QString &path)
{
beginInsertRows(QModelIndex(), list.size(), list.size());
TableItem item;
item.filename = path;
QFile file(path);
item.size = file.size();
item.status = StatusNew;
list << item; // Why Assign first? Maybe not required
for (int i = list.size() - 1; i > 0; i--)
{
list[i] = list[i-1];
}
list[0] = item; // set newly added item at the top
endInsertRows();
}

Copying part of QTableView

So I have a question very closely related to another question I've seen on here but when I tried posing my question there I got no responses, I'm hoping by asking this as a fresh question someone can help me out. Basically I want simply copy a portion of my table that I've created so that I can paste it to an excel file. Here's what I have:
QAbstractItemModel *abmodel = ui.tableview->model();
QItemSelectionModel *model = ui.tableview->selectionModel();
QModelIndexList list = model->selectionIndexes();
qSort(list);
QModelIndex index = list.first();
for(int i = 0; i < list.size(); i++)
{
QModelIndex index = list.at(i);
QString text = abmodel->data(index).toString();
copy_table.append(text);
if(index.row() != previous.row())
{
copy_table.append('\n');
}
else
{
copy_table.append('\t');
}
previous = index;
}
QClipboard *clipboard = QApplication::clipboard();
clipboard->setText(copy_table);
This will copy a column fine, but when I attempt to copy a row or say a 2x2 subtable the row index gets messed up, incorrectly assigning the row index for the values. Any thoughts?
Well, already figured it out, sorry anyone that wasted their time and looked.
void TestCopyTable::on_pushButton_copy_clicked()
{
QAbstractItemModel *abmodel = ui.tableView->model();
QItemSelectionModel * model = ui.tableView->selectionModel();
QModelIndexList list = model->selectedIndexes();
qSort(list);
if(list.size() < 1)
return;
QString copy_table;
QModelIndex last = list.last();
QModelIndex previous = list.first();
list.removeFirst();
for(int i = 0; i < list.size(); i++)
{
QVariant data = abmodel->data(previous);
QString text = data.toString();
QModelIndex index = list.at(i);
copy_table.append(text);
if(index.row() != previous.row())
{
copy_table.append('\n');
}
else
{
copy_table.append('\t');
}
previous = index;
}
copy_table.append(abmodel->data(list.last()).toString());
copy_table.append('\n');
QClipboard *clipboard = QApplication::clipboard();
clipboard->setText(copy_table);
}
I wrote some code based on Phil's to copy the selection when the user types Control-C.
I subclassed QTableWidget and overrode keyPressEvent():
void MyTableWidget::keyPressEvent(QKeyEvent* event) {
// If Ctrl-C typed
// Or use event->matches(QKeySequence::Copy)
if (event->key() == Qt::Key_C && (event->modifiers() & Qt::ControlModifier))
{
QModelIndexList cells = selectedIndexes();
qSort(cells); // Necessary, otherwise they are in column order
QString text;
int currentRow = 0; // To determine when to insert newlines
foreach (const QModelIndex& cell, cells) {
if (text.length() == 0) {
// First item
} else if (cell.row() != currentRow) {
// New row
text += '\n';
} else {
// Next cell
text += '\t';
}
currentRow = cell.row();
text += cell.data().toString();
}
QApplication::clipboard()->setText(text);
}
}
Output example (tab-separated):
foo bar baz qux
bar baz qux foo
baz qux foo bar
qux foo bar baz
Regarding the cdline:
qSort(cells); // Necessary, otherwise they are in column order
currently(20190118) it brings a warning:
Warnung: 'qSort >' is deprecated: Use std::sort
so my solution to replace the line with:
std::sort(cells.begin(),cells.end());
Compile, Run OK -> so far so good. But Question: Benefit of this cdline?
I found there is no one. Made several Test with copy from gui and parsing it to excel. Everything was fine even with the scenario 2x2 or othe XxY.

Resources