Qt trying to enable scrolling slightly beyond last element in QTableView - c++

I'm making a sort of an Excel-type application in which I can load a tab-delimited text file and I am able to edit cells... etc
It's useable but I have an issue related to me allowing the user to "freeze" a number of columns/rows. ("Frozen" rows/columns can only be one of the first ones and are then "frozen", i.e. always displayed even when scrolling)
The whole frozen Col/Row is working but I would like the user to be able to scroll slightly past the last Col/Row in order to be able to only ever display full cells.
Right now when reaching the end of the scrollbar I end up with a partial leftmost column and topmost row because it's only displaying up to the last full col/row and not going a wee bit further for all content to be displayed fully.
I've tried doing adding some space to the maximum scrollbar value once everything is loaded in the table but it seems to have no effect :
table->horizontalScrollBar()->setMaximum(table->horizontalScrollBar()->maximum() + t->horizontalScrollBar()->singleStep()*2);
I tried multiple values too.
(Edit) There may be some Qt code that "snaps" the QTableView viewport back to the edge of the last cell automatically...
(Edit2) I connected verticalScrollbar's rangeChanged() signal to a custom slot with the following code:
void MyTableView::onRangeChanged(int min, int max) {
QScrollBar *sender = verticalScrollBar();
int newVMax = max + 20;
sender->blockSignals(true);
sender->setRange(min, newVMax);
sender->blockSignals(false);
}
Sadly there is definitely a snapback mechanic when scrolling to the end of verticalScrollbar...
Gif of snap back issue
(Edit3) The snap back may be related to:
void QHeaderViewPrivate::setScrollOffset(const QScrollBar *scrollBar, QAbstractItemView::ScrollMode scrollMode)
{
Q_Q(QHeaderView);
if (scrollMode == QAbstractItemView::ScrollPerItem) {
if (scrollBar->maximum() > 0 && scrollBar->value() == scrollBar->maximum())
q->setOffsetToLastSection();
else
q->setOffsetToSectionPosition(scrollBar->value());
} else {
q->setOffset(scrollBar->value());
}
}
mainly:
if (scrollBar->maximum() > 0 && scrollBar->value() == scrollBar->maximum())
q->setOffsetToLastSection();

Related

Unity Slider mapped to list<float>?

I currently have a list<float> that are arranged in an increasing order. My sliders min.value is the lowest value of my list (i.e. first element of my list) and sliders max.value is equal to the last item of my list.
What I want to do is that whenever my slider is at a specific value or +-0.1 to one of the elements on my list, I Want to be able to get the index out that specific element to perform a task.
Any suggestions?
Someone asked for code, I don't even like this code since it only gives me the right value once I press "play" from zero, but then it removes my data, so I can't go back with the slider
this code is inside update void, and isPlaying is true when I press a "play" button
if(isPlaying){
timeSlider.value += Time.deltaTime;
timer = timeSlider.value;
print(timeSlider.value);
if((newTimes[0]>=(timer-0.1f)) && (newTimes[0]<=(timer+0.1f))){
print("time: " + newTimes[0]+ " at run time: " + timer);
NewTimes.RemoveAt(0);
}
}
You can set the slider to use whole numbers in the inspector and use the value as your index?
My first thought would be:
Set Slider Steps to Floats in your List
-> Perform task on List[currentSliderStep] as needed

How to have a Button Change images from three different pictureboxes whilst making the previous invisible

I have 3 picture boxes added on my Visual Basic and I have one button
essentially i want the button to display the next image when its pressed and to hide the previous image (all images are set to invisible on startup)
i've tried to do stuff like
If pic1.visible then
pic2.visible = true
pic3.visible = true
else
pic 1 .visible = true
end if
etc etc
Instead of basing your if-statement logic on the visibility of other images, I would suggest to create a counter that will keep track of the active image.
To keep it simple, have the counter loop between 1, 2 and 3 (i.e. clicking the button 4 times would make the counter == 1). Then simply have your if-statement logic based on the current value of the counter.
For instance:
if (counter == 1) {
pic1.show();
pic2.hide();
pic3.hide();
} else if (counter == 2) {
...
}
You can use switch statements if you'd like but I think this should give you a general idea.

Get data from selected row of gtk treeview - gtkmm, c++

I have a GTK application that has a window with a treeview and a button. When the button is clicked I need to get the data from the first (and only) column of the selected row in the treeview.
This is the class for the columns:
class ModelColumns:
public Gtk::TreeModel::ColumnRecord{
public:
ModelColumns(){ add(m_port_name); }
Gtk::TreeModelColumn<Glib::ustring> m_port_name;
};
This is like in the example here but with only one column: http://www.lugod.org/presentations/gtkmm/treeview.html
This is the button click signal handler at the moment:
tvPorts is the treeview widget
tvPortsList is the listStore for the treeview
static
void on_btnPortSelectOK_clicked (){
Glib::RefPtr<Gtk::TreeSelection> selection = tvPorts->get_selection();
Gtk::TreeModel::iterator selectedRow = selection->get_selected();
//Now what?
//Need to get data from selected row to display it.
}
I have searched the documentation and many examples to try and find out what to do next but can't find any examples for gtkmm, I can only find examples for c or python implementations.
As far as I can tell, I need to get a TreeRow object from my iterator (selectedRow) how do I do this?
Thanks.
Update:
I am now using this code and it almost works.
The only problem is that it prints the previous selection.
The first time I select something and then press the button it prints only a new line. The second time it prints what was selected the first time, the third prints the second, etc.
Glib::RefPtr<Gtk::TreeSelection> selection = tvPorts->get_selection();
Gtk::TreeModel::iterator selectedRow = selection->get_selected();
Gtk::TreeModel::Row row = *selectedRow;
Glib::ustring port = row.get_value(m_Columns.m_port_name);
printf("\nselected port: %s", port.data());
This seems odd.
(m_Columns is an instance of the ModelColumns class)
Update 2:
Fixed the problem by adding fflush(stdout);
It all works now, thanks.
The docs say to simply dereference the iter to get the TreeRow:
Gtk::TreeModel::Row row = *iter; // 'iter' being your 'selectedRow'
std::cout<<row[0];

EM_EXGETSEL does not relate to text selection order. How do I do determine the caret position in a piece of selected text?

When I do:
SendMessage(editControlHWND, EM_EXGETSEL, 0, (LPARAM)&charRange);
I get the selected range of text. However, I want to know where the caret is in this selection, ie at the end, OR at the beginning.
ie, has the user selected the text 'backwards', as in something like dragging from right to left.
EM_EXGETSEL will always have the smaller number in cpMin, so clearly does not relate to the selection order.
I obviously can't get the caret position with EM_EXGETSEL for comparison in this situation because a chunk of stuff is already selected.
Is there any way to get the caret's current individual position (so that I can compare it to cpMin/cpMax)? Or alternatively, is there any way of determining where the caret is in a block of selected text?
EDIT:
My explanation for why I want to do this:
I insert text programmatically into a read-only RichEdit control which the user can select text from. However, when text is added at the end, it has to move the caret to the end and insert the text, and this can happen when text has been selected/the user is currently selecting text.
It's this last one that is the bother. I use EM_EXGETSEL and EM_EXSETSEL to get and set the selected text before and after text is programmatically entered. By default, EM_EXGETSEL will always put the smaller number in cpMin, meaning that if the user is currently selecting text backwards (ie right to left), and text is added to the control, the position of the caret in the selection area changes from the beginning to the end, because I feed these numbers directly into EM_EXSETSEL. I know that EM_EXSETSEL is capable of backwards selection (I have tested this with the larger number in cpMin and the smaller one in cpMax), but EM_EXGETSEL does not give any indication that the user has selected text backwards.
Therefore I need to know the caret position to compare it to cpMin or cpMax to check if it is at the beginning of the selection or the end, and act accordingly.
Just came across this post while looking into the same problem.
I was able to resolve by tracking changes to the selection notified by EN_SELCHANGE and comparing the results at WM_LBUTTONUP.
There's no easy way to do this. EM_GETSEL and EM_EXGETSEL return the range of the current selection. Only if there is no selection do they return the position of the caret.
Note that the caret can't be in a block of selected text - it is always at the end or beginning.
You could probably implement a solution fairly easily by sub-classing the control, and using EM_GETSEL to query and store the position of the caret after any key or mouse input. E.g.
LRESULT WINAPI EditControlSubclassProc(...)
{
LRESULT lRes = CallWindowProc(...); // call original window procedure
if ((uMsg >= WM_KEYFIRST && uMsg <= WM_KEYLAST)
|| (uMsg >= WM_MOUSEFIRST && uMsg <= WM_MOUSELAST))
{
DWORD dwStart, dwEnd;
SendMessage(hWnd, EM_GETSEL, (WPARAM)&dwStart, (LPARAM)&dwEnd);
if (dwStart == dwEnd)
{
// no current selection, so simply store the position of the caret
g_dwCaretPos = dwStart;
}
}
return lRes;
}
This way you will always know where the caret was the last time there was input that didn't result in a selection. You can then compare it to the range of the selection to determine which end the selection was anchored at, and therefore know the caret is at the other end.
It seems that EM_LINEFROMCHAR and EM_LINEINDEX with (WPARAM == -1) can be used.
I've managed to do this, although it was a little complicated to get there due to my lack of understanding on the concept of sub-classing. ><
I used Spy++ to look at what messages were being sent when I was selecting text.
This was apparently exclusively EM_GETPASSWORDCHAR messages.
So I did:
case EM_GETPASSWORDCHAR:
{
if(hwnd == editControlHwnd)
{
CHARRANGE tempCharRange;
SendMessage(editControlHwnd, EM_EXGETSEL, 0, (LPARAM)&tempCharRange);
SetSelectionDirection(tempCharRange.cpMin, tempCharRange.cpMax);
return CallWindowProc(oldWndProc, hwnd, uMsg, wParam, lParam);
}
}
With:
void SubWindow::SetSelectionDirection(int newCpMin, int newCpMax) //Set selectionDirection to false if selecting backwards, true if selecting forwards
{
if((newCpMin != prevCpMin) && (newCpMax == prevCpMax))
selectionDirection = false;
else if((newCpMin == prevCpMin) && (newCpMax != prevCpMax))
selectionDirection = true;
prevCpMin = newCpMin;
prevCpMax = newCpMax;
}
Where bool selectionDirection;, int prevCpMin; and int prevCpMax; are private class member variables.
This way I compare the new selected area with the previously selected area to see which end has changed, and which one hasn't.
I don't know if what I'm doing here is a bad way of actually working this out, but if there's a better way to do this, I haven't found it. That's why I'm posting this as the answer in the event that it helps someone else in my position.

Colour report rows that contain the same product name

I have a list of products and I am trying to alternate the colour between each product (grey, white, grey, white, and so on). I understand how to use colour formatting based on a condition such as the following link: example followed. However I dont know how to get it to look at the previous line on the report and check whether it holds the same product name. If it does, then colour the row the same colour, else the alternate colour.
I've setup an example report in the application: Application 67666 - Colour Row by Product example. I have two products in the report so I'm trying to get 3 grey lines and then 3 white lines, if I had more products it would then go back to grey and so on.
Link:apex.oracle.com
workspace: apps2
user: user
password: DynamicAction2
Please could I be directed in the right direction, JavaScript and Dynamic Actions shout out to me as in the example link however its looking at the previous row which is getting me all stuck.
I can't think of another solution than javascript really. There is possibly using lag in the sql, but only to use it to determine where the row color should change. You could use the value of the column in a html expression of a column and put it in a class, but you still need to iterate over it with javascript anyway. So it seems less fiddly to just use javascript.
Inline CSS:
table.report-standard tr.normalRow td{
background-color: green;
}
table.report-standard tr.altRow td{
background-color: red;
}
This will override the default style, but you will need to tune this to your demands. For example, the color change on :hover of the row. I prefer steering the style through assigning classes and then define the rules in css than to directly assign css through javascript (which would place it in style tags, ugh).
Dynamic action: change row colour
After Refresh, Region, Product Report
True action: execute javascript code, fire on page load checked
$('td[headers="PRODUCT"]', this.triggeringElement).each(function(){
var lCurrRow = $(this).closest('tr'),
lPrevRow = lCurrRow.prev(),
lPrevVal = lPrevRow.find('td[headers="PRODUCT"]').text();
console.log(lPrevVal + ' - ' + $(this).text());
//if value on previous row differs from the that on the current row
//then change the class
//if the value didnt change, then use the same class as the previous row
if ( lPrevVal != $(this).text() ){
if ( lPrevRow.hasClass('normalRow') ){
lCurrRow.addClass('altRow');
} else {
lCurrRow.addClass('normalRow');
};
} else {
if ( lPrevRow.hasClass('normalRow') ){
lCurrRow.addClass('normalRow');
} else {
lCurrRow.addClass('altRow');
};
};
})
Check your solution on apex.oracle.com, I implemented it there.