How can I select text in Gtk::TextView:
starting from where the cursor is
n number of characters backwards
The documentation from developer.gnome.org doesn't seem to help.
The selection isn't done in the Gtk::TextView itself but in the associated Gtk::TextBuffer. While I'm not sure why exactly this design choice was done I'm at least clear about the consequence: Selections may be shared between multiple Gtk::TextViews when they share the same buffer. This may be desirable or not but it's how “they” have done it.
The buffer of a Gtk::TextView can be obtained with
Glib::RefPtr< TextBuffer > get_buffer ()
Returns the Gtk::TextBuffer being displayed by this text view.
The reference count on the buffer is not incremented; the caller of this function won’t own a new reference.
Then, the Gtk::TextBuffer provides
void Gtk::TextBuffer::select_range (const iterator& ins, const iterator& bound)
This function moves the “insert” and “selection_bound” marks simultaneously.
If you move them in two steps with move_mark(), you will temporarily select a region in between their old and new locations, which can be pretty inefficient since the temporarily-selected region will force stuff to be recalculated. This function moves them as a unit, which can be optimized.
ins Where to put the “insert” mark.
bound Where to put the “selection_bound” mark.
The current cursor position can be obtained with
Glib::RefPtr Gtk::TextBuffer::get_insert()
Returns the mark that represents the cursor (insertion point).
Equivalent to calling get_mark() to get the mark named “insert”, but very slightly more efficient, and involves less typing.
The returned Gtk::TextMark can be “converted” to a Gtk::TextIter by using
TextIter Gtk::TextMark::get_iter().
Additionally, Gtk::TextBuffer provides a variety of get_iter_at functions to get the Gtk::TextBuffer::iterators for distinct parameters.
A note in general:
To learn a powerful widget API by the reference manual, is something I would consider as tedious.
In the case of gtkmm, there is a serious alternative:
Programming with gtkmm 3
(which is available in other languages as well).
Chapter 11 is about TextView and might help to get the “big picture”.
Related
QSpinBox* spinright[size] = {ui->norm_spinBox_2,
ui->norm_spinBox_3,
ui->norm_spinBox_4,
ui->norm_spinBox_5,
ui->norm_spinBox_6,
ui->norm_spinBox_7,
ui->norm_spinBox_8};
I'd like to be able to access this array in two spots in my program. However, if there is a better alternative for this solution I’m all ears. I tried to create a function that could be called for this program; however it started to get long and dragged out that it was becoming less worth it to go this route.
This is how I've set up the Hierarchy. My overall attempt is to make some buttons appear and disappear when a button is pressed. If it's possible to make the vertical layouts disappear then this would be a better way to go.
In the end I'll take whatever solution, that may be offered here.
Thank you for your help.
void GuiTest::setLabelsVisible(int index, bool visible){
QLabel* labels[norm_size] = {ui->norm_label_2,
ui->norm_label_3,
ui->norm_label_4,
ui->norm_label_5,
ui->norm_label_6,
ui->norm_label_7,
ui->norm_label_8};
labels[index]->setVisible(visible);
}
the best way to do this, I found, would to go this direction. Instead of setting this list of objects as global just have separate functions that will manipulate the structure in some way.
Background: I'm developing application using Qt 5.5.1, compiling with msvc2013. In this app I use my own implementation of QTableView, along with custom QStyledItemDelegate (needed custom cell editing) and QAbstractTableModel. I intend this view to work with massive amount of data that I wrap inside mentioned model. I allow the user few data editing options, custom sorting, 'invalid' rows windup etc.
The problem: scrolling speed of my QTableView subclass is slow - it gets slower the more table is shown (by resizing window), e.g. ~250 cells shown (in fullscreen) = slow, ~70 cells shown (small window) = fast.
Whad did I try so far:
First was to check if my model is slowing things down - I have measured times (using QTime::elapsed()) reading 10k samples and it shown 0 or 1ms. Then I have simply altered QTableView::data method to always return predefined string and not acquire any real data.
QVariant DataSet_TableModel::data(const QModelIndex &index, int role) const
{
if (role == Qt::ItemDataRole::DisplayRole) {
return QVariant("aRatherLongString"); //results in slow scrolling
//return QVariant("a"); // this instead results in fast scrolling
}
else return QVariant();
}
As you can see, the speed seems to be affected by number of characters vieved per cell, and not by underlying connections to data source.
In my custom implementation of QStyledItemDelegate I have tried same 'trick' as above - this time overriging displayText method:
QString DataSet_TableModel_StyledItemDelegate::displayText(const QVariant &value, const QLocale &locale) const
{
return "a" //fast
// return "aRatherLongString"; //slow
// return QStyledItemDelegate::displayText(value, locale); //default
}
After some thought with a friend we concluded that maybe we could disable drawing/painting/updating of cells until whole scroll action is done. It might cause some flickering, but it's worth a try. Unfortunately we dont really know how to aproach this. We have everriden QTableView methods: scrollContentsBy(int dx, int dy) and verticalScrollbarAction(int action) - we have captured scroll action properly (either method intercepts it) and tried to somehow disable repainting like this:
void DataSet_TableView::verticalScrollbarAction(int action) {
this->setUpdatesEnabled(false);
QTableView::verticalScrollbarAction(action);
this->setUpdatesEnabled(true);
}
...but it did not have any visible effect.
How should we approach it? Do we need to use setUpdatesEnabled() on items that are put inside cells directly? (not sure what those are - widgets?)
Here are screenshots taken as part of testing this problem:
Predefined text, no calls to underlying data structure - slow scrolling, 'full screen'
Predefined text, no calls to underlying data structure - fast scrolling, windowed
Request: Could you kindly help me pinpoint the cause of this and suggest solution if possible? Is it limitation of the classes that I use?
First of all, you should also run your application in release mode to check your perfomance, in my experience, the performance decreases greatly when using debug mode.
Secondly, you need to be aware that the model data method and delegates methods are called every time you resize, scroll, focus out, right click etc. These actions trigger those methods to be called for each displayed cell, therefore you would need to make sure that you don't do any unnecessary processing.
The items inside cells are delegates that call their own methods (eg: paint).
Some C++ specific optimisations would be helpful in the implementation of these methods, like using a switch instead of an if statement, see explanation here and here. The usage of Conditional (Ternary) Operators might also speed up the things, more information here, here and some information about expensive checkings here.
Also, QVariant handles text in different ways, as exemplified below, you should try both ways and check if there is any difference in speed. Some conversions are more expensive than others.
v = QVariant("hello"); // The variant now contains a QByteArray
v = QVariant(tr("hello")); // The variant now contains a QString
I've got a pretty old MFC application that's been touched by many people over the years (most of them probably not even CS guys) and it follows, what I like to call the "anarchy design pattern."
Anyway, one of the dialogs has a series of 56 vertical sliders and check boxes. However, there are additional sliders and checkboxes on the dialog as shown below.
Now, the problem is that the additional sliders and checkboxes take on IDs that are in sequence with the slider/checkbox series of the dialog. My task is to add more sliders and checkboxes to the series (in the blank space in the Slider Control group box) Unfortunately, since IDC_SLIDER57 through IDC_SLIDER61 are already in the dialog (same goes for the checkboxes), existing code, such as the snippet below will break:
pVSlider = (CSliderCtrl *)GetDlgItem(IDC_SLIDER1+i);
Is there a better way to modify the resource file without doing it manually? I've seen a third party tool called ResOrg that looks like it'll help do what I want, but the software is a bit pricey, especially since I'll only use it once. I guess I can give the demo a try, but the limitations might restrict me.
FYI, I'm using Visual C++ 6.0 (yes...I know, don't laugh, it's being forced upon me).
Instead of writing:
pVSlider = (CSliderCtrl *)GetDlgItem(IDC_SLIDER1+i);
you could write:
pVSlider = (CSliderCtrl *)GetDlgItem(GetSliderID(i));
where GetSlider is a function that returns the id of slider number i.
GetSlider function
int GetSliderID(int nslider)
{
static int sliderids[] = {IDC_SLIDER1, IDC_SLIDER2, IDC_SLIDER3, .... IDC_SLIDERn};
ASSERT(nslider < _countof(sliderids));
return sliderids[nslider];
}
With this method the IDC_SLIDERn symbols dont need to have sequential values.
I have written a text editor program in C++ that has simple commands: LEFT, RIGHT, HOME, END, BACKSPACE, DELETE, INSERT, and now I need to perform the UNDO and REDO functions. In my program the user must be able to undo no more than the last ten commands. I would like to use a vector implementation to accomplish this, but I have no idea how to set this up. I'm not sure how to store the cursor position and the character into a vector. Can someone offer some help?
#ifndef CURSOR_H
#define CURSOR_H
#include <stdlib.h>
#include <iostream>
template <class Object>
class Cursor;
// Incomplete Declaration
template <class Object>
class CNode
{
public:
CNode( const Object & theElement = Object( ), CNode * n = NULL ) : element( theElement ), next( n ) { }
Object element;
CNode *next;
friend class Cursor<Object>;
};
template <class Object>
class Cursor
{
public:
Cursor( );
bool isEmpty( ) const;
void makeEmpty( );
void left ( );
void right ( );
void del ( ); //This is the delete operation. I named it del instead of delete as delete conflicts with a C++ keyword.
void back ( );
void insert( const Object & x );
void home ( );
void end ( );
void undo ( );
private:
void printText ( ) ;
CNode<Object> *header;
CNode<Object> *cursorPosition;
};
//#include "Cursor.cpp"
#endif
You want to use a deque so that you can add and remove from the front or the back; when adding a command, add it to the back, when undoing remove it from the back, and when you reach 11 commands remove one from the front.
Look at the Memento Design Pattern and also in GOF
It exists for this very specific requirement. You may have to use it in combination with other Design patterns (e.g. Command, Iterator, FlyWeight etc)
Memento Intent
Without violating encapsulation,
capture and externalize an object's
internal state so that the object can
be restored to this state later.
Command Intent
Encapsulate a request
as an object, thereby letting you
parameterize clients with different
requests, queue or log requests, and
support undoable operations.
Some other things to consider:
In general, you do not want to apply undo/redo to cursor movements (i.e. they would have no affect on the limit of ten commands limit). When undoing/redoing a deletion or insertion of text, of course you have to place the cursor in the proper place before performing the operation. If the user is typing a number of characters without performing any cursor movements or corrections (backspace), generally these are treated as a single unit when applying undo/redo.
Congrats on including undo/redo. It's a great feature in any sort of editor. It can get tricky, still. Here are some thoughts for you (all hand-waving, no code).
I recommend learning about the Command Design Pattern. What you want to do is design a 'Command' class, an instance of which can "Do" a single command (like insert the letter 'A'), as well as "Undo" itself.
When the user invokes some command (like to add the letter 'A') you 'new' a Command, define its "Do" to insert 'A', also define its "Undo" to remove A, then add it to the top of your undo list, and then "Do" it.
Don't limit your undos to only 10. Why not make it infinite?
Whatever structure you use to make a list of undoable Commands, the usual behavior is that if you have undo'd to some level, and then begin to edit at that point, then all the redos above the current level should be discarded.
For each operation you want to be able to undo (i.e. presumably insert, backspace and del, but not the cursor movements), we can list the "undo" procedure:
insert -> position the cursor at that character and issue a del
del -> position the cursor at the following character and issue an insert
backspace -> position the cursor at the following character and issue an insert
Unfortunately, your cursors use pointers, and when you undo a delete/backspace the newly allocated CNode may not be at the same address as previously, which could invalidate an earlier undo step trying to use that pointer address. Options include:
some additional data structures to track which pointers have been invalidated in this way, and repopulate them with new values if the corresponding elements are recreated (painful)
find a more deterministic way to find the correct index in the CNode list
an absolute index into the document (but that may be difficult to calculate and slow to move to)
save your cursor movement in your undo history
mixing 10 substantive edits (del, backspace, insert) with an arbitrary number of interspersed cursor movements requires a dynamically sized container, and you'd be carrying quite a bit of "verbose baggage"
you could hang a dynamic list of cursor movements off each element in a fixed-sized list of each substantive edit (not much better though)
(As is, your Cnode list doesn't appear double-linked, so I don't see how you can move left without a very painful reiteration through the "document" from the header element...?)
After sorting out this indexing/cursor-movement issue, you must decide between:
after each operation, use a deque to save the undo information:
struct History
{
an indicator of which operation to undo (e.g. enum Op { left, right, insert, del... })
only for insert operations: an object value
}
then have some on-undo processing function that reads these History records and coordinates the operations they describe, or
when an operation is performed, push a function object onto your deque that encodes the undo and redo operations (in terms of calls to the Cursor object methods), so that actually doing an undo or redo operation just involves executing that object (i.e. the undo/redo operation is a "black box" parcelled up at edit time) / this is more elegant and flexible, but probably less familiar to beginning/intermediate programmers so may be harder to get right. The boost library has good supporting functions for this.
I agree with the others about capturing undoable commands as the "do" command is executed.
I'd also suggest working through the list periodically and combining undo commands.
For example, if your undo commands are:
Delete A, Delete B, Delete C, Left-Cursor, Left-Cursor, Right-Cursor, Left-Cursor.
Convert that to merely,
Delete "ABC", Left-Cursor(2).
That way, when the user does undo actions, they don't see every single keystroke hit. Instead, the undo happens in logical groups.
We're using Infragistics grid (most probably, we'll have 8.2 version at the end) and we want to configure row/cells appearances "on-demand" in order to be able to provide sort of "dynamic appearance".
For example, I want some cell to be red or green, depending on its value. We might want to tweak other characteristics as well (font, size, image, etc).
A perfect place to do it would be some event, that happen before a cell gets repainted... But it seems there is no such event in Infragistics...
Or am I wrong? Any help?
Clarification: I'm talking about WinForms Infragistics UltraGrid
I had to do exactly this with the IG WebGrid a few years back, and it was ... shall we say ... painful. However, the WebGrid had the advantage of a single render point -- once the HTML was emitted, we were set!
For dealing with this in WinGrid, I tried a variety of different events, both on the grid and the datasource, and met with abject failure every step of the way. The only event I got to work was Paint, which will likely create a performance issue.
For Paint, here's what I hacked together. I'm not proud of this code, and I likely wouldn't put it in production, but here it is anyway (C#):
private void UltraGrid1_Paint(object sender, System.Windows.Forms.PaintEventArgs e)
{
foreach (UltraGridRow r in UltraGrid1.Rows)
{
foreach (UltraGridCell c in r.Cells)
{
if (c.Text == "foo")
c.Appearance.BackColor = Color.Green;
}
}
}
and VB:
Private Sub UltraGrid1_Paint(ByVal sender As System.Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles UltraGrid1.Paint
For Each r As UltraGridRow In UltraGrid1.Rows
For Each c As UltraGridCell In r.Cells
If c.Text = "foo" Then
c.Appearance.BackColor = Color.Green
End If
Next
Next
End Sub
There is an event. I don't remember exactly what it's called, but it's got to be something like 'DataRowBound' or 'ItemDataBinding', etc..
Also, this article might help.
Not that this has anything to do with your question, but I'd stay away from heavy use of Infragistics controls - they're very heavy and will slow down the page rendering process considerably. Just my $0.02.
We have finally come up with two solutions for that problem.
For some of the dynamic content we use grid elements appearance and reinitialize it "on-demand".
For the extremely resource-critical appearance we use UltraGrid.DrawFilter (see also IUIElementDrawFilter interface).