I have little problem with scrollbar.
The problem is there is no separator anymore if i move the scrollbar back to the top again.
#include <FL/Fl.H>
#include <FL/Fl_Window.H>
#include <FL/Fl_Scroll.H>
#include <FL/Fl_Box.H>
#define BW 200 //box width
#define BH 50 //box height
#define SEP 10 //separator
int main(){
Fl_Window win(500, 300);
Fl_Scroll *scr=new Fl_Scroll(10,10,win.w()-20,win.h()-20);
scr->color(FL_GREEN);
int col=scr->w()/BW;
int c=0,line=SEP;
for(int i=1;i<=20;i++){
Fl_Box *b = new Fl_Box(scr->x()+SEP+(c*(BW+SEP)),scr->y()+line,BW,BH);
b->box(FL_FLAT_BOX);
b->color(FL_RED);
c += 1;
if(c == col){
c = 0;
line += (BH + SEP);
}
}
new Fl_Box(SEP,scr->y()+line-SEP,SEP,SEP);
win.show();
return Fl::run();
}
Thanks.
Can't really tell what the reason is for that behaviour but
If the last Fl_Box is removed, the bottom separator disappears.
If a box is added before the loop, it doesn't lose the top line
new Fl_Box(SEP,0,SEP,SEP);
Related
Sorry for the massive block of code ;w;
I'm learning C++, and this is an assignment I'm stuck on- I'm supposed to be making a brick wall with alternating rows offset by 1/2 bricks, and I'm supposed to be using a nested loop to do so.
I've got the functions to draw the full brick and half bricks, and I've successfully been able to create a full line of 9 bricks(9 being how many bricks can span the window) and I'm stuck on the next step. I need to make the program draw the next line after the first one is finished, but "\n" and "cout << endl;" only affect the main window and not the "TurtleWindow" that OpenCV opens. All I have in that regard is that it has something to do with the "changePosition" command, but I'm not sure how to add that in to my loop. If I set position to some specific (x, y) coords, then wouldn't it just keep setting the "bricks" in that position every loop?
Any help would be appreciated, I feel like I'm so close to the solution but this is stumping me...
// BrickWall.cpp : This file contains the 'main' function. Program execution begins
//and ends there.
//
#include <iostream>
#include "opencv2/core.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/highgui.hpp"
#include <stdio.h>
#include <math.h>
using namespace cv;
using namespace std;
#define M_PI 3.14159265358979323846264338327950288
#define degToRad(angleInDegrees) ((angleInDegrees) * M_PI / 180.0)
char wndname[] = "TurtleWindow";
Mat image = Mat::zeros(500, 500, CV_8UC3);
Scalar WHITE(255, 255, 255);
const int DELAY = 1;
Point _curPosition(250, 250);
int _direction = 0;
void init()
{
imshow(wndname, image);
waitKey(DELAY);
}
//
// Move the pen to the given coordinates without leaving a mark
//
// Note (0,0) refers to the upper left corner
// (500,500) refers to the bottom right corner
//
void changePosition(int x, int y)
{
_curPosition.x = x;
_curPosition.y = y;
}
//
// point in the direction given in degrees
// 0 ==> point right
// 90 ==> point down
// 180 ==> point left
// 270 ==> point up
//
void changeDirection(int direction)
{
_direction = direction;
}
//
// Moves the pen forward the given number of pixels
// Note leaves a mark creating a line from the previous point
// to the new point
//
void moveForward(int nPixels)
{
int x = static_cast<int>(round(nPixels * cos(degToRad(_direction))));
int y = static_cast<int>(round(nPixels * sin(degToRad(_direction))));
Point newPoint = Point(x + _curPosition.x, y + _curPosition.y);
line(image, _curPosition, newPoint, WHITE);
_curPosition = newPoint;
// cout << "moved to " << newPoint.x << "," << newPoint.y << endl;
imshow(wndname, image);
waitKey(DELAY);
}
void fullBrick()
// changePosition(25, 25);
{
changeDirection(0);
moveForward(50);
changeDirection(90);
moveForward(20);
changeDirection(180);
moveForward(50);
changeDirection(270);
moveForward(20);
changeDirection(0);
moveForward(50);
}
void halfBrick()
//changePosition(25, 45);
{
changeDirection(0);
moveForward(25);
changeDirection(90);
moveForward(20);
changeDirection(180);
moveForward(25);
changeDirection(270);
moveForward(20);
}
int main()
{
int counter;
int counterWall;
counterWall = 0;
counter = 0;
init();
changePosition(25, 25);
while (counter < 20)
{
do
{
changeDirection(0);
moveForward(50);
changeDirection(90);
moveForward(20);
changeDirection(180);
moveForward(50);
changeDirection(270);
moveForward(20);
changeDirection(0);
moveForward(50);
counterWall++;
} while (counterWall < 9);
counter++;
}
waitKey();
}
edit: thanks everyone for the advice! I was fully intending to use a nested loop in the end(and did use one, so no lost points there!) and was able to realize there was nothing stopping me from looping the bricks like a snake. I had to turn the assignment in before I could try any of the changes you guys offered, but I'll be sure to keep them in mind for future assignments!
and here's a link to the picture of the final product, I've never been happier to see a brick wall in my life
Brick Wall Picture
I have a QTableWidget that has a column (#3) that needs more space than others. I want to resize all columns to their contents, and give priority to column #3. If column #3 pushes the table's width past what's available, I want column #3 to be truncated with '...' without a horizontal scrollBar.
The screenshot below is the simplest example of the behavior I'm chasing, but I've had to manually adjust the column widths. I want the table to do this automatically.
The following code shows examples of what I've tried on QTableWidget, but none have worked. I've provided inline comments on why the following methods do not work:
table->horizontalHeader()->setStretchLastSection(true);
table->resizeColumnsToContents();
Thank you to anyone who volunteers your time to help me with this.
#include <QApplication>
#include <QTableWidget>
#include <QStringList>
#include <QRect>
#include <QLayout>
#include <QDialog>
#include <QHeaderView>
#include <iostream>
int main( int argc, char* argv[] )
{
QApplication a(argc, argv);
QDialog* d = new QDialog();
d->setLayout( new QVBoxLayout() );
QTableWidget* table = new QTableWidget(1,4);
QStringList headers = {"1", "2", "3", "4"};
table->setHorizontalHeaderLabels(headers);
table->setItem(0, 0, new QTableWidgetItem("1"));
table->setItem(0, 1, new QTableWidgetItem("22222"));
table->setItem(0, 2, new QTableWidgetItem("33333333333333333333333333333"));
table->setItem(0, 3, new QTableWidgetItem("4"));
// Do nothing
//
// The table exceeds the dimensions of the dialog,
// and we get a horizontal scrollbar
// This also results in a horizontal scrollbar
//
// table->horizontalHeader()->setStretchLastSection(true);
// Resizing the columns introduces a horizontal scrollbar, and
// prevents the user from from changing column width
//
// table->resizeColumnsToContents();
// The table fits, but all columns are equally spaced.
// (We want column 3 to take up as much space as possible)
//
// table->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
// Columns are resized to their contents,
// but column 3 is not truncated and we get a horizontal scrollBar
//
// table->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);
d->layout()->addWidget( table );
d->show();
return a.exec();
}
This should work, try it out
#include <QApplication>
#include <QTableWidget>
#include <QStringList>
#include <QRect>
#include <QLayout>
#include <QDialog>
#include <QHeaderView>
#include <QScrollBar>
#include <iostream>
int main( int argc, char* argv[] )
{
QApplication a(argc, argv);
QDialog* d = new QDialog();
d->setLayout( new QVBoxLayout() );
QTableWidget* table = new QTableWidget(1,4);
QStringList headers = {"1", "2", "3", "4"};
table->setHorizontalHeaderLabels(headers);
table->setItem(0, 0, new QTableWidgetItem("1"));
table->setItem(0, 1, new QTableWidgetItem("22222"));
table->setItem(0, 2, new QTableWidgetItem("33333333333333333333333333333"));
table->setItem(0, 3, new QTableWidgetItem("4"));
// Do nothing
//
// The table exceeds the dimensions of the dialog,
// and we get a horizontal scrollbar
// This also results in a horizontal scrollbar
//
// table->horizontalHeader()->setStretchLastSection(true);
// Resizing the columns introduces a horizontal scrollbar, and
// prevents the user from changing column width
//
//resize table
d->layout()->addWidget( table );
d->show();
table->resizeColumnsToContents();
int tableWidth = table->width();
int columsWidth = 0;
int maxColumnWidth = 0;
int maxColumnIndex = 0;
int w = 0;
for(int n = 0; n < table->columnCount(); n++)
{
w = table->columnWidth(n);
columsWidth += w;
if(w > maxColumnWidth)
{
maxColumnWidth = w;
maxColumnIndex = n;
}
}
if(columsWidth > tableWidth)
{
int delta = columsWidth - tableWidth + table->horizontalScrollBar()->height();
maxColumnWidth -= delta;
if(maxColumnWidth < 0)
maxColumnWidth = 0;
table->setColumnWidth(maxColumnIndex, maxColumnWidth);
}
// This table fits, but all the columns are equally spaced.
// (We want column 3 to take up as much space as possible)
//
// table->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
// Columns are resized to their contents,
// but column 3 is not truncated and we get a horizontal scrollBar
//
// table->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);
return a.exec();
}
Get back to me if you have any problems with this code.
My problem is that when i run programm it runs normally for around 10-20 seconds, and then it glitch out. You can see further what's happening on the video.
https://youtu.be/YOlhjQFTzZc
This error is hunting me for over a month, First i thought this was some mistake in making shorter Render function. But not.
You can see it here.
void Render(char * image_place, int object_x, int object_y)
{
SDL_Surface * object_image = IMG_Load(image_place);
SDL_Rect object_position;
object_position.x=object_x;
object_position.y=object_y;
SDL_BlitSurface(object_image, NULL, ekran, &object_position);
}
But when i started "researching" on this topic more, i discovered that it happen even without using this function!
Here is code from the video:
#include <iostream>
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
#include <SDL2/SDL_mixer.h>
#include <SDL2/SDL_ttf.h>
#include <windows.h>
#include <time.h>
using namespace std;
//SDL
SDL_Window * okno;
SDL_Surface * ekran;
SDL_Rect pozycja_obramowki;
SDL_Event zdarzenie;
SDL_Rect tlo_pos;
//zmienne
int x_obraz=0;
int y_obraz=0;
int main(int argc, char*args[])
{
SDL_Init(SDL_INIT_EVERYTHING);
okno = SDL_CreateWindow("LevelEditor",SDL_WINDOWPOS_CENTERED,SDL_WINDOWPOS_CENTERED, 1280, 720, NULL);
ekran = SDL_GetWindowSurface(okno);
while(true)
{
{//render
SDL_Surface * tlo = IMG_Load("biel.png");
tlo_pos.x=0;
tlo_pos.y=0;
SDL_BlitSurface(tlo,NULL, ekran, &tlo_pos);
SDL_Surface * obramowka = IMG_Load("obramowka.png");
pozycja_obramowki.x=x_obraz;
pozycja_obramowki.y=y_obraz;
SDL_BlitSurface(obramowka,NULL, ekran, &pozycja_obramowki);
}
{//zdarzenia
if(SDL_PollEvent(&zdarzenie))
{
if(zdarzenie.type==SDL_QUIT)
{
return 0;
}
}
}
{//sterowanie
if(GetAsyncKeyState(VK_RIGHT)) {x_obraz=x_obraz+5;}
if(GetAsyncKeyState(VK_LEFT)) {x_obraz=x_obraz-5;}
if(GetAsyncKeyState(VK_UP)) {y_obraz=y_obraz-5;}
if(GetAsyncKeyState(VK_DOWN)) {y_obraz=y_obraz+5;}
}
{//fps end & odswiezanie ekranu
SDL_UpdateWindowSurface(okno);
}
}
}
If i wrote something wrong or explained anything wrong, feel free to comment on this post. Any help will be useful, thanks ; )
You shouldn't call IMG_Load repeatedly. (I suspect that you're running out of memory pretty quickly.)
Load all images at startup and store pointers to the resulting surfaces.
// Moved out of the loop
SDL_Surface * tlo = IMG_Load("biel.png");
SDL_Surface * obramowka = IMG_Load("obramowka.png");
while(true)
{
// As before, but without declaring the variables mentioned above.
}
Intention
I wrote a VTK application that generates a spiral using vtkPoints > vtkPolyLine > vtkPolyData > vtkPolyDataMapper and displays it. This works fine, if done static at the initialization of the program.
Now, I want to add new data points dynamically. The intention is to visualize measurements in real time, so new data will be added in certain intervals.
Issues
Currently, I just implemented a TimerEvent to update the vtkPoints and vtkPolyLine. But, the program just shows the static data generated before the vtkRenderWindowInteractor was started. I also tried to use "Modified()" and "Update()" calls to nearly all objects, tried to remove, regenerate and add a new actor to the renderer -- but without success! I added my C++ code below...
Related-Questions
The following mailing list question is about this issues, but the solution given doen't work for me:
http://public.kitware.com/pipermail/vtkusers/2006-November/038377.html
The following question seems to be related, but there are no useful answers:
VTK: update data points in renderWindow at every simulation timestep
Questions
How to tell VTK that the vtkPolyData object has changed?
Which of the VTK UsersGuide should I probably have a closer look at?
Details / Source Code
I'm using Visual Studio Community 2017 and VTK 8.0.0, both compiled as Win32 target.
#include <vtkAutoInit.h>
VTK_MODULE_INIT(vtkRenderingOpenGL2);
VTK_MODULE_INIT(vtkRenderingContextOpenGL2);
VTK_MODULE_INIT(vtkRenderingVolumeOpenGL2);
VTK_MODULE_INIT(vtkInteractionStyle);
VTK_MODULE_INIT(vtkRenderingFreeType);
#include <vtkSmartPointer.h>
#include <vtkRenderWindow.h>
#include <vtkRenderer.h>
#include <vtkConeSource.h>
#include <vtkPolyDataMapper.h>
#include <vtkActor.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkProperty.h>
#include <vtkPoints.h>
#include <vtkPolyLine.h>
vtkSmartPointer<vtkPoints> points = vtkSmartPointer<vtkPoints>::New();
vtkSmartPointer<vtkPolyLine> polyLine = vtkSmartPointer<vtkPolyLine>::New();
int numOfPoints = 0;
double t = 0;
void NextPoint() {
double x = t * cos(t);
double y = t * sin(t);
points->InsertNextPoint(x, y, t);
polyLine->GetPointIds()->InsertNextId(numOfPoints);
numOfPoints++;
t += 0.1;
}
vtkSmartPointer<vtkPolyData> generateEllipse() {
// Add some points so we actually see something at all...
for (int i = 0; i < 100; ++i) {
NextPoint();
}
vtkSmartPointer<vtkCellArray> cells = vtkSmartPointer<vtkCellArray>::New();
cells->InsertNextCell(polyLine);
vtkSmartPointer<vtkPolyData> polyData = vtkSmartPointer<vtkPolyData>::New();
polyData->SetPoints(points);
polyData->SetLines(cells);
return polyData;
}
class vtkTimerCallback : public vtkCommand
{
public:
static vtkTimerCallback *New()
{
vtkTimerCallback *cb = new vtkTimerCallback;
cb->TimerCount = 0;
return cb;
}
virtual void Execute(vtkObject *vtkNotUsed(caller), unsigned long eventId,
void *vtkNotUsed(callData))
{
if (vtkCommand::TimerEvent == eventId)
{
NextPoint(); // Add another point to polyData
++this->TimerCount;
cout << this->TimerCount << endl;
}
}
private:
int TimerCount;
};
int main(int argc, char** argv) {
vtkSmartPointer<vtkRenderWindow> renderWindow =
vtkSmartPointer<vtkRenderWindow>::New();
vtkSmartPointer<vtkRenderWindowInteractor> rwi = vtkSmartPointer<vtkRenderWindowInteractor>::New();
rwi->SetRenderWindow(renderWindow);
vtkSmartPointer<vtkPolyData> data = generateEllipse();
vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
mapper->SetInputData(data);
vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
actor->SetMapper(mapper);
actor->GetProperty()->SetDiffuseColor(255, 255, 0);
vtkSmartPointer<vtkRenderer> renderer = vtkSmartPointer<vtkRenderer>::New();
renderWindow->AddRenderer(renderer);
renderer->AddActor(actor);
renderer->ResetCamera();
renderWindow->Render();
// Add Timer Event...
rwi->Initialize();
vtkSmartPointer<vtkTimerCallback> cb = vtkSmartPointer<vtkTimerCallback>::New();
rwi->AddObserver(vtkCommand::TimerEvent, cb);
int timerId = rwi->CreateRepeatingTimer(100); // every 100ms
std::cout << "timerId: " << timerId << std::endl;
// Start Displaying...
rwi->Start();
return 0;
}
the problem is that the cells are not stored by pointer - when you call cells->InsertNextCell(polyLine); the data is copied, not pointed to, in order to create an efficient storage of the cells in an array (the whole implementation is actually in the header of vtkCellArray so you can check it out). So then when you update polyLine, it has no effect in the polydata, because the polydata have their own copy that you did not update. The following code works for me (you have to expose the polydata and the cellArray):
virtual void Execute(vtkObject *vtkNotUsed(caller), unsigned long eventId,
void *vtkNotUsed(callData))
{
if (vtkCommand::TimerEvent == eventId)
{
NextPoint(); // Add another point to polyData
cells->Initialize(); // reset the cells to remove the old spiral
cells->InsertNextCell(polyLine); // re-insert the updated spiral
cells->Modified(); // required to update
data->Modified(); // required to update
++this->TimerCount;
cout << polyLine->GetNumberOfPoints() << endl;
renderWindow->Render(); // refresh the render window after each update
}
}
Yesterday I worked out an alternative solution using a vtkProgrammableDataObjectSource as DataSource. Tomj's solution is the more direct and simple solution... However, there is no C++ Example Code at vtk.org that explains how to use vtkProgrammableDataObjectSource and I had to work it out by trial and error. So I'll post it here, as it might help others:
#include <vtkAutoInit.h>
VTK_MODULE_INIT(vtkRenderingOpenGL2);
VTK_MODULE_INIT(vtkRenderingContextOpenGL2);
VTK_MODULE_INIT(vtkRenderingVolumeOpenGL2);
VTK_MODULE_INIT(vtkInteractionStyle);
VTK_MODULE_INIT(vtkRenderingFreeType);
#include <vtkSmartPointer.h>
#include <vtkRenderWindow.h>
#include <vtkRenderer.h>
#include <vtkConeSource.h>
#include <vtkPolyDataMapper.h>
#include <vtkActor.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkProperty.h>
#include <vtkPoints.h>
#include <vtkPolyLine.h>
#include <vtkProgrammableFilter.h>
#include <vtkCallbackCommand.h>
#include <vtkPolyDataStreamer.h>
#include <vtkProgrammableDataObjectSource.h>
vtkSmartPointer<vtkProgrammableDataObjectSource> pDOS = vtkSmartPointer<vtkProgrammableDataObjectSource>::New();
vtkSmartPointer<vtkRenderer> renderer = vtkSmartPointer<vtkRenderer>::New();
vtkSmartPointer<vtkPoints> points = vtkSmartPointer<vtkPoints>::New();
vtkSmartPointer<vtkPolyLine> polyLine = vtkSmartPointer<vtkPolyLine>::New();
int numOfPoints = 0;
double t = 0;
void NextPoint() {
double x = t * cos(t);
double y = t * sin(t);
points->InsertNextPoint(x, y, t);
polyLine->GetPointIds()->InsertNextId(numOfPoints);
numOfPoints++;
t += 0.1;
}
void generateEllipse(void *caller) {
vtkProgrammableDataObjectSource *pDOS = vtkProgrammableDataObjectSource::SafeDownCast((vtkObjectBase*)caller);
vtkSmartPointer<vtkCellArray> cells = vtkSmartPointer<vtkCellArray>::New();
cells->InsertNextCell(polyLine);
vtkSmartPointer<vtkPolyData> polyData = vtkSmartPointer<vtkPolyData>::New();
polyData->SetPoints(points);
polyData->SetLines(cells);
pDOS->SetOutput(polyData);
}
int counter2 = 0;
void TimerCallbackFunction(vtkObject* caller, long unsigned int vtkNotUsed(eventId), void* clientData, void* vtkNotUsed(callData)) {
cout << "timer callback: " << counter2 << endl;
// To avoid globals we can implement this later...
// vtkSmartPointer<vtkProgrammableDataObjectSource> pDOS =
// static_cast<vtkProgrammableDataObjectSource*>(clientData);
vtkRenderWindowInteractor *rwi =
static_cast<vtkRenderWindowInteractor*>(caller);
NextPoint();
pDOS->Modified();
rwi->Render();
renderer->ResetCamera(); // Optional: Reposition Camera, so it displays the whole object
counter2++;
}
int main(int argc, char** argv) {
vtkSmartPointer<vtkRenderWindow> renderWindow =
vtkSmartPointer<vtkRenderWindow>::New();
vtkSmartPointer<vtkRenderWindowInteractor> rwi = vtkSmartPointer<vtkRenderWindowInteractor>::New();
rwi->SetRenderWindow(renderWindow);
pDOS->SetExecuteMethod(&generateEllipse, pDOS);
vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
mapper->SetInputConnection(pDOS->GetOutputPort());
vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
actor->SetMapper(mapper);
actor->GetProperty()->SetDiffuseColor(255, 255, 0);
renderWindow->AddRenderer(renderer);
renderer->AddActor(actor);
renderer->ResetCamera();
renderWindow->Render();
// Add Timer Event...
vtkSmartPointer<vtkCallbackCommand> timerCallback = vtkSmartPointer<vtkCallbackCommand>::New();
timerCallback->SetCallback(TimerCallbackFunction);
rwi->Initialize();
rwi->CreateRepeatingTimer(100);
rwi->AddObserver(vtkCommand::TimerEvent, timerCallback);
// Start Displaying...
rwi->Start();
return 0;
}
I'm wondering about this member-function's scroll_to(TextBuffer::iterator& iter, double within_margin = 0) parameter within_margin. The API says this:
The effective screen for purposes of this function is reduced by a margin of size within_margin.
...
Parameters
within_margin margin as a [0.0,0.5] fraction of screen size.
I just don't get it. What and when does this parameter modifies the behaviour? Every langugage-binding of Gtk includes the same description. I've written a small application, so you can change the passed argument to the parameter yourself.
#include <gtkmm.h>
#include <iostream>
#include <string>
using namespace std;
Gtk::TextView* text_view;
void on_add_button_clicked();
void on_scroll_button_clicked();
int main(int argc, char* argv[]) {
Glib::RefPtr<Gtk::Application> app = Gtk::Application::create(argc, argv, "org.gtkmm.examples.base");
Gtk::Window window;
Glib::RefPtr<Gdk::Monitor> primary_monitor = window.get_screen()->get_display()->get_primary_monitor();
Gdk::Rectangle monitor_size;
primary_monitor->get_geometry(monitor_size);
// half-size of primary-monitor
int width = monitor_size.get_width() / 2;
int height = monitor_size.get_height() / 2;
window.set_default_size(width, height);
window.set_title(__FILE__);
Gtk::Grid grid;
grid.set_row_spacing(5);
grid.set_column_spacing(5);
Gtk::ScrolledWindow scroll_window;
text_view = new Gtk::TextView();
text_view->set_editable(true);
scroll_window.add(*text_view);
scroll_window.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
scroll_window.set_hexpand(true);
scroll_window.set_vexpand(true);
Glib::RefPtr<Gtk::TextBuffer> text_buffer = text_view->get_buffer();
text_buffer->set_text("Hello!\n");
text_view->set_buffer(text_buffer);
grid.attach(scroll_window, 0, 0, 2, 2);
Gtk::Button add_button("add text");
add_button.signal_clicked().connect(sigc::ptr_fun(&on_add_button_clicked));
grid.attach_next_to(add_button, scroll_window, Gtk::POS_BOTTOM, 1, 1);
Gtk::Button scroll_button("scroll to somewhere");
scroll_button.signal_clicked().connect(sigc::ptr_fun(&on_scroll_button_clicked));
grid.attach_next_to(scroll_button, add_button, Gtk::POS_RIGHT, 1, 1);
window.add(grid);
window.show_all();
return app->run(window);
}
void on_add_button_clicked() {
Glib::RefPtr<Gtk::TextBuffer> text_buffer = text_view->get_buffer();
for (int i = 0; i != 100; ++i) {
text_buffer->insert_at_cursor("foobar\n");
}
}
void on_scroll_button_clicked() {
Glib::RefPtr<Gtk::TextBuffer> text_buffer = text_view->get_buffer();
Gtk::TextBuffer::iterator it = text_buffer->end();
text_view->scroll_to(it, 0.49);
}
You can compile the code with g++ -o scroll scroll.cpp -Wall -pedantic-errors `pkg-config gtkmm-3.0 --cflags --libs` .
Thank you
If margin is 0, then scroll_to() is free to put the target anywhere in the screen. If margin is 0.45, for example, then scroll_to() will put the target in the middle 10% of the screen, if possible.
The reason you don't see this in your example, is because you are scrolling to the end iterator, and it's not possible to scroll view so that the end of the text is displayed in the middle of the screen. (Some text views include extra space after the text in order to make this possible; Gtk::TextView doesn't.)