Documentation Index
Fetch the complete documentation index at: https://mintlify.com/fltk/fltk/llms.txt
Use this file to discover all available pages before exploring further.
Overview
Fl_Scroll is a container widget that allows you to view and navigate content larger than the visible area using scrollbars. It automatically displays horizontal and/or vertical scrollbars when child widgets extend beyond the container bounds.
Header: <FL/Fl_Scroll.H>
Inherits: Fl_Group
Key Features
- Automatic scrollbar management
- Configurable scrollbar visibility modes
- Supports scrolling large widget collections
- Can pan around a single canvas widget
- Customizable scrollbar positioning
- Optional always-visible scrollbars
Use Cases
- Long lists of widgets
- Large canvas/drawing areas
- Content viewers
- Scrollable forms
- Image viewers
- Text editors with custom rendering
- Container for Fl_Pack or Fl_Flex
Layout Algorithm
Fl_Scroll calculates its scrollable area based on:
- Computes bounding box of all child widgets using their positions (x, y) and sizes (w, h)
- Outside labels are not included in bounding box calculation
- Displays scrollbars if content exceeds visible area
- Adjusts visible area when scrollbars appear/disappear
- Scrolls content by changing the x() and y() of child widgets
Bounding Box Calculation
To include space outside the natural bounding box (e.g., for outside labels), add invisible Fl_Box widgets at the corners:
Fl_Scroll scroll(100, 100, 200, 200);
Fl_Box(100, 100, 1, 1); // Top-left corner marker
// ... add widgets with outside labels ...
scroll.end();
Constructor
Fl_Scroll(int X, int Y, int W, int H, const char *L = 0)
Creates an Fl_Scroll container with both scrollbars enabled.
X position of the scroll container
Y position of the scroll container
Width of the visible area
Height of the visible area
Optional label (default: NULL)
Type Constants
enum {
HORIZONTAL = 1, // Only horizontal scrollbar
VERTICAL = 2, // Only vertical scrollbar
BOTH = 3, // Both scrollbars (default)
ALWAYS_ON = 4, // Flag: always show scrollbars
HORIZONTAL_ALWAYS = 5, // Horizontal always, vertical never
VERTICAL_ALWAYS = 6, // Vertical always, horizontal never
BOTH_ALWAYS = 7 // Both scrollbars always visible
}
Set using type():
scroll->type(Fl_Scroll::VERTICAL); // Only vertical
scroll->type(Fl_Scroll::BOTH_ALWAYS); // Both always visible
scroll->type(0); // No scrollbars
Default Behavior
- Type:
Fl_Scroll::BOTH
- Scrollbars appear automatically when content exceeds visible area
- Scrollbars disappear when content fits
Fl_Scrollbar scrollbar; // Vertical scrollbar
Fl_Scrollbar hscrollbar; // Horizontal scrollbar
These are public members that can be directly accessed:
// Change scrollbar colors
scroll->scrollbar.color(FL_GRAY);
scroll->hscrollbar.color(FL_GRAY);
// Access scrollbar values
int pos = scroll->scrollbar.value();
Use scrollbar.align() to change scrollbar positions:
// Left vertical scrollbar, top horizontal scrollbar
scroll->scrollbar.align(FL_ALIGN_LEFT | FL_ALIGN_TOP);
// Default: right and bottom
scroll->scrollbar.align(FL_ALIGN_RIGHT | FL_ALIGN_BOTTOM);
Only the alignment flags in scrollbar are used. Flags in hscrollbar are ignored.
xposition() / yposition()
int xposition() const
int yposition() const
Gets the current horizontal or vertical scrolling position.
Returns: Current scroll position in pixels
void scroll_to(int x, int y)
Scrolls to the specified position.
Horizontal scroll position in pixels
Vertical scroll position in pixels
int scrollbar_size() const
void scrollbar_size(int newSize)
Gets or sets the pixel size of scrollbar troughs.
Scrollbar width in pixels, or 0 to use global Fl::scrollbar_size()
Default: 0 (uses global setting)
Normally you should use Fl::scrollbar_size(int) to set scrollbar size globally for UI consistency. Only use this method if you need a widget-specific override.
Child Management
resize()
void resize(int X, int Y, int W, int H) override
Resizes the Fl_Scroll container and recalculates scrollbars.
clear()
Removes and deletes all child widgets.
delete_child()
int delete_child(int n) override
Deletes child widget by index.
Index of child to delete (0-based)
Box Type Recommendations
If child widgets are packed together in a solid rectangle:
scroll->box(FL_NO_BOX);
// or
scroll->box(FL_DOWN_FRAME);
scroll->box(FL_UP_FRAME);
This produces the best output with minimal redrawing.
For Sparse Layouts
If child widgets are sparsely arranged:
scroll->box(FL_DOWN_BOX);
// or other _BOX types
May cause blinking during redraw. Use Fl_Double_Window to eliminate blinking:
Fl_Double_Window *win = new Fl_Double_Window(...);
Fl_Scroll *scroll = new Fl_Scroll(...);
scroll->box(FL_DOWN_BOX);
#include <FL/Fl.H>
#include <FL/Fl_Double_Window.H>
#include <FL/Fl_Scroll.H>
#include <FL/Fl_Button.H>
int main(int argc, char** argv) {
Fl_Double_Window window(300, 400, "Scrollable Button List");
// Create scroll container
Fl_Scroll scroll(10, 10, 280, 380);
scroll.type(Fl_Scroll::VERTICAL); // Only vertical scrollbar
// Add many buttons (extends beyond visible area)
for (int i = 0; i < 50; i++) {
char label[20];
sprintf(label, "Button %d", i);
Fl_Button *btn = new Fl_Button(10, 10 + i * 30, 260, 25, label);
}
scroll.end();
window.end();
window.show(argc, argv);
return Fl::run();
}
#include <FL/Fl.H>
#include <FL/Fl_Window.H>
#include <FL/Fl_Scroll.H>
#include <FL/Fl_Box.H>
#include <FL/fl_draw.H>
// Custom canvas widget
class Canvas : public Fl_Box {
public:
Canvas(int X, int Y, int W, int H) : Fl_Box(X, Y, W, H) {
box(FL_FLAT_BOX);
color(FL_WHITE);
}
void draw() override {
Fl_Box::draw();
// Use x() and y() for positioning
// Test clipping to optimize drawing
if (fl_not_clipped(x() + 50, y() + 50, 100, 100)) {
fl_color(FL_BLACK);
fl_rect(x() + 50, y() + 50, 100, 100);
}
// Draw more content...
}
};
int main() {
Fl_Window win(400, 300, "Canvas Scroll");
Fl_Scroll scroll(0, 0, 400, 300);
// Large canvas (larger than window)
Canvas *canvas = new Canvas(0, 0, 800, 600);
scroll.end();
win.resizable(scroll);
win.end();
win.show();
return Fl::run();
}
#include <FL/Fl.H>
#include <FL/Fl_Window.H>
#include <FL/Fl_Scroll.H>
#include <FL/Fl_Pack.H>
#include <FL/Fl_Tabs.H>
#include <FL/Fl_Group.H>
#include <FL/Fl_Button.H>
int main() {
Fl_Window win(350, 400, "Scrollable Panels");
Fl_Scroll scroll(10, 10, 330, 380);
// Pack that contains collapsible Fl_Tabs panels
Fl_Pack pack(10, 10, 310, 0);
pack.spacing(5);
for (int i = 0; i < 10; i++) {
char label[20];
sprintf(label, "Panel %d", i + 1);
Fl_Tabs *tabs = new Fl_Tabs(0, 0, 310, 80);
Fl_Group *grp = new Fl_Group(0, 25, 310, 55, label);
// Add content to group
Fl_Button *btn = new Fl_Button(10, 30, 100, 25, "Action");
grp->end();
tabs->end();
}
pack.end();
scroll.end();
win.end();
win.show();
return Fl::run();
}
Fl_Scroll scroll(0, 0, 400, 300);
scroll.type(Fl_Scroll::BOTH_ALWAYS); // Scrollbars always visible
// Scrollbars remain visible even if content fits
// Scroll to specific position
scroll->scroll_to(100, 200);
// Scroll to bottom
int max_y = /* calculate based on content height */;
scroll->scroll_to(scroll->xposition(), max_y);
// Get current position
int current_x = scroll->xposition();
int current_y = scroll->yposition();
Best Practices
When using a single child canvas:
class MyCanvas : public Fl_Widget {
void draw() override {
// Use x() and y() for positioning
int draw_x = x() + offset_x;
int draw_y = y() + offset_y;
// Test clipping to optimize
if (fl_not_clipped(draw_x, draw_y, item_w, item_h)) {
// Draw item
}
}
};
Box Type Selection
// Packed children (best performance)
scroll->box(FL_NO_BOX); // or FL_DOWN_FRAME
// Sparse children (use double buffering)
Fl_Double_Window *win = new Fl_Double_Window(...);
Fl_Scroll *scroll = new Fl_Scroll(...);
scroll->box(FL_DOWN_BOX);
Outside Labels
Add corner markers for widgets with outside labels:
Fl_Scroll scroll(100, 100, 200, 200);
Fl_Box(100, 100, 1, 1); // Top-left
Fl_Input *inp = new Fl_Input(150, 120, 60, 30, "Name:");
inp->align(FL_ALIGN_LEFT); // Outside label
scroll.end();
FLUID Limitations
When designing in FLUID:
- Can only lay out objects that fit without scrolling
- FLUID won’t show scrollbars
- Leave space for scrollbars in your design
Restrictions
You cannot use Fl_Window as a child of Fl_Scroll. Clipping is not conveyed to child windows, causing them to draw over scrollbars and neighboring objects.
Notes
- Default type:
Fl_Scroll::BOTH
- Scrollbars appear/disappear automatically (unless ALWAYS_ON)
- Outside labels are not included in bounding box
- Scrolling changes child widget positions (x, y)
- Use
fl_not_clipped() in canvas widgets to optimize drawing
- Scrollbar alignment controls all scrollbar positions
- Default scrollbar size: global
Fl::scrollbar_size()
See Also