How to disable scrolling in a QML ScrollView (or TextArea) - qt

I want to use a QML TextArea on a mobile device, where the user cannot scroll by swiping through the contents. Instead I want the widget to grow with the content (which I can do by utilizing contentHeight).
But I am unable to disable the scrolling behavior. TextArea has this scrolling behavior because it inherits from ScrollView.

You can use ScrollView's property flickableItem to change or disable scrolling behavior. In your case I'd use:
TextArea {
flickableItem.interactive: false
}
If you want to do something else, check out QML's Flickable, you should be able to use all its properties like with any other Flickable.

Related

How to scroll with arrow keys in a Kirigami ScrollablePage?

The Qt QML based mobile/desktop convergent UI framework Kirigami provides a QML type ScrollablePage to support scrolling through content. Placing any visual QML item into it automatically makes it scrollable if it's larger than the ScrollablePage itself:
ScrollablePage is a Page that holds scrollable content, such as ListViews.
Scrolling and scrolling indicators will be automatically managed.
Kirigami.ScrollablePage {
id: root
//The rectangle will automatically be scrollable
Rectangle {
width: root.width
height: 99999
}
}
(source)
This provides scrollbars and allows scrolling with the mouse wheel, two-finger-scrolling with the touchpad and flicking ("click and throw") scrolling as we're used to from touchscreen devices.
However, it does not allow scrolling with any keyboard keys (Arrow Up / Down, Page Up / Down). How can I make that possible? The usual approach of doing Keys.onUpPressed: scrollBar.decrease() does not work because the ScrollablePage's scrollbar is not accessible as part of its public API.
Instructions
Use a Flickable to wrap the content items you put into your ScrollablePage. Then evaluate key press events in the Flickable and in response execute flick() to scroll the view. Example (combining examples from the Kirigami manual and from the Qt manual):
Kirigami.ScrollablePage {
id: root
Flickable {
focus: true
topMargin: 20; leftMargin: 20; bottomMargin: 20; rightMargin: 20
Keys.onUpPressed: flick(0, 800)
Keys.onDownPressed: flick(0, -800)
Rectangle {
width: root.width
height: 5000
}
}
}
Details and Explanation
While you can't access the scrollbar, you can access what the scrollbar uses to move the view: a Flickable instance. You just have to wrap it around the page's content. If you don't, ScrollablePage internally uses ScrollView to wrap your page's content in a Flickable anyway, but then you don't have a reference on it to execute flick().
Executing flick() does the same as when the user flicks the element, so the scrollbar position etc. will be updated alright.
If it still does not work, then (1) maybe you give too small pixel/second values to Flickable::flick() for scrolling to be visible or (2) maybe the initial Flickable::flickDeceleration values on your platform are messed up. These values are platform specific, so it can require some experimentation. On some platforms, setting them to zero during a flick() will help, while under Linux this is exactly the value preventing any scroll movement.
It is not necessary to enable ScrollablePage::keyboardNavigationEnabled for the above solution to work, since that is only for moving the currentItem of suitable content with the arrow keys (see below), and not for scrolling in general. It will even prevent ordinary scrolling in case your page content is an item view (ListView, GridView etc.).
Alternative solution for item views
If the content of your ScrollablePage is an item view (any QML object that has a currentItem property, such as ListView or GridView), then instead of wrapping that content in a Flickable just enable ScrollablePage::keyboardNavigationEnabled. It will allow you to move the currentItem with the Arrow Up and Arrow Down keys. That's what one usually wants for these views, even though it's not scrolling but rather keyboard navigation.

How to disable clicking through item in qml?

The application I currently work on has a map as a background, and above it various other dialogs(views) with more than one view inside can be opened. When some of the dialogs is active, when dragging over it's background map is moving like there's nothing above it. Does someone know how to disable this? I don't want map to react on clicks or anything inside a dialog.
The project is organised so that each dialog is implemented in separate qml file:
I have each qml file for each dialog, and each component of application (map), so
when you click, for example on settings tab in scrollable horizontal list, settings tab is opened from qml that holds all dialogs, including bottom and top of the app
each dialog is above map and has a 50% transparent background, with related images and buttons in it
I want to disable dragging map while dragging over dialog's background. I tried with setting this to each dialog:
MouseArea {
anchors.fill: parent
onClicked: mouse.accepted = true
}
(parent is Item that holds all elements of a dialog), but this doesn't work.
If I'm understanding your question correctly, it should suffice to set the MouseArea's propagateComposedEvents to false.

Overlaying and positioning windows

Let's say I have a widget that cannot allow a child widget to be displayed on top of it- yet that's the look I need. I'm assuming the only way to accomplish that look would be to make the child widget into its own window.
How can I make that "child" window always on top of the "parent", and position it to always be at the bottom (with a predefined margin) and centered horizontally?
It should respond to resizing of the parent window as well.
A good example would be like a controlbar for video
(in fact- I would guess that in fullscreen mode VLC is essentially doing something like this... is it?)
EDIT: here is my current widgets layout: http://i.imgur.com/NcRLmrd.png
Note that the seekbar is not displaying over the video
The child widget should have Qt::Tool window flag, and parent widget should be set as parent widget of the child as usual. This way it will be a top-level widget and will always be on top of the parent.
You should position the child widget manually. For example, you can install an event filter on the parent widget and react on Move and Resize event types.

React when a scrollbar activates

I have a TextInput in a container. I need the horizontal scrolling capabilities of the container so that when the textInput is to big it allows me to scroll to see the text on the left and right. The scrollbar track and thumb were set to null so I can see the text.
trackSkin: ClassReference(null);
thumbUpSkin: ClassReference(null);
thumbOverSkin: ClassReference(null);
thumbDownSkin: ClassReference(null);
thumbSkin: ClassReference(null);
Now I want to listen to an event or watch a property that changes when the horizontal scrollbar activates. Then I would like to set a padding on the container or left and right property on the text input so that the left and right arrows do not get in the way of the user to see the first and last characters.
Thanks
Before adding listeners and accessing the HScrollBar of the Scroller, you may find this setting/variable of some use: measuredSizeIncludesScrollBars
From the API: (Please forgive the terrible formatting)
If true, the Scroller's measured size includes the space required for the visible scroll bars, otherwise the Scroller's measured size depends only on its viewport.
Components like TextArea, which "reflow" their contents to fit the available width or height may use this property to stabilize their measured size. By default a TextArea's is defined by its widthInChars and heightInChars properties and in many applications it's preferable for the measured size to remain constant, event when scroll bars are displayed by the TextArea skin's Scroller.
In components where the content does not reflow, like a typical List's items, the default behavior is preferable because it makes it less likely that the component's content will be obscured by a scroll bar.
In the event this doesn't work, I would probably add an event listener attached to the lifecycle of the Scroller. During that event handling, I would check to see if the Scrollbar was null or not. If it wasn't, I would store it off to the side, but not before adding a listener to its "show" and "hide" event. That way, you can kick off whatever you need to whenever the scrollbar changes its state.

QListView Transparent Scrollbar with Image in QT

I am having QListWidget, i want to have a Transparent Scrollbar with Image.
Initially that scrollbar should be hidden on scroll only it should show.
How i Can achieve this in Qt ?
Any examples or ideas are welcomed.
How i can apply image to Listview Scrollbar.
Here are the three things you can look at to be able to control the scroll bar for most kinds of widgets in Qt:
VerticalScrollBarPolicy
HorizontalScrollBarPolicy
enum Qt::ScrollBarPolicy.
To be able to track how the user interacts with your QListWidget or any Widget for that matter you need to subclass it and implement the virtual methods from the QWheelEvent and possibly the QKeyEvent.
Scrolling is typically done with the mouse wheel and with the keyboard arrow keys and sometimes page-up and page-down and spacebar. I haven't done a lot with QListWidget, but you should double check which keyboard events/mouse events trigger scrolling.
These events will cause scrolling event even after you set either or both of the ScrollBarPolicies for the widget to be Qt::ScrollBarAlwaysOff.
First you should put in the constructor of your widget
this->setVerticalScrollBar(Qt::ScrollBarAlwaysOff);
this->setHorizontalScrollBar(Qt::ScrollBarAlwaysOff);
So you just need to setMouseTracking(true) for the widget (so that it tracks more than just the clicks) and reimplement at the very least wheelEvent(), and when a wheel event occurs, set the vertical/horizontal scroll bar policies to true and call update on your widget.
If you want to turn the scrollbars back off after a few milliseconds after they have started scrolling, you will need to create a QTimer in your constructor for your subclassed widget and connect it to a slot that sets the scroll bar polices on the timeout. Then you start/restart that timer every time the user does a wheelEvent().
As far as applying an image to the ListView Scrollbar, you should look into subclassing QAbstractScrollBar, if you want to actually put an image on it or change the way it looks. Setting up some tool buttons may also be the way to go if you are trying to put buttons with different icons in place of the scrollbar.

Resources