How to do a horizontal scroll on mouse wheel scroll?
It looks like he's just mapping the mousewheel event to scrolling the area. In IE, this is really easy by just using the doScroll()
method - this will scroll the horizontal bar by the amount the vertical bar would normally scroll by. Other browsers don't support the doScroll()
method, so you have to live with scrolling by an arbitrary amount instead:
var mouseWheelEvt = function (event) {
if (document.body.doScroll)
document.body.doScroll(event.wheelDelta>0?"left":"right");
else if ((event.wheelDelta || event.detail) > 0)
document.body.scrollLeft -= 10;
else
document.body.scrollLeft += 10;
return false;
}
document.body.addEventListener("mousewheel", mouseWheelEvt);
tkinter: binding mousewheel to scrollbar
Perhaps the simplest solution is to make a global binding for the mousewheel. It will then fire no matter what widget is under the mouse or which widget has the keyboard focus. You can then unconditionally scroll the canvas, or you can be smart and figure out which of your windows should scroll.
For example, on windows you would do something like this:
self.canvas = Canvas(...)
self.canvas.bind_all("<MouseWheel>", self._on_mousewheel)
...
def _on_mousewheel(self, event):
self.canvas.yview_scroll(-1*(event.delta/120), "units")
Note that self.canvas.bind_all
is a bit misleading -- you more correctly should call root.bind_all
but I don't know what or how you define your root window. Regardless, the two calls are synonymous.
Platform differences:
- On Windows, you bind to
<MouseWheel>
and you need to divideevent.delta
by 120 (or some other factor depending on how fast you want the scroll) - on OSX, you bind to
<MouseWheel>
and you need to useevent.delta
without modification - on X11 systems you need to bind to
<Button-4>
and<Button-5>
, and you need to divideevent.delta
by 120 (or some other factor depending on how fast you want to scroll)
There are more refined solutions involving virtual events and determining which window has the focus or is under the mouse, or passing the canvas window reference through the binding, but hopefully this will get you started.
How to scroll the horizontal scrollbar in an iFrame from the parent frame?
There are at least two things wrong with your example:
if ("iframeWithWideContent" in document.body){
document.body.onmousewheel = mouseWheelEvt;
}else{
document.body.addEventListener("DOMMouseScroll", mouseWheelEvt);
}
Here you test for iframeWithWideContent
being present in document.body and you rely on that condition to use either …onmousewheel
or …addEventListener
. These are completely unrelated. Moreover, addEventListener requires an extra argument.
As the answer you link to describes, Firefox doesn't support onmousewheel (it's non-standard anyway), so you should detect whether that property is present or not:
if ("onmousewheel" in document.body)
document.body.onmousewheel = mouseWheelEvt;
else
document.body.addEventListener("DOMMouseScroll", mouseWheelEvt, true);
Just in case you didn't know, this is (more or less) the right way of feature detection (in fact, I should have tested if DOMMouseScroll was available before applying it).
According to this answer, contentWindow
is the iframe's window object.
Update: I made another test case and got it working in Firefox and Chrome (it probably works in other WebKit-based browsers, too).
iframescrolling.html:
<!DOCTYPE html>
<html>
<head>
<meta charset=utf-8>
<title><iframe> horizontal scrolling test</title>
<style>
* { padding: 0; margin: 0; border: 0 }
#large { background: #aaa; height: 5000px; width: 5000px }
</style>
</head>
<body>
<iframe id="iframeWithWideContent" src="iframecontent.html" width="500" height="300"></iframe>
<div id="large"></div>
<script>
var myIframe = document.getElementById("iframeWithWideContent");
myIframe.onload = function () {
var mouseWheelEvt = function (e) {
var event = e || window.event;
// the first is for Gecko, the second for Chrome/WebKit;
var scrEl = this.parentNode || event.target.parentNode;
if(event.wheelDelta)
var d = 60;
else
var d = -60;
if (document.body.doScroll)
document.body.doScroll(event.wheelDelta>0?"left":"right");
else if ((event.wheelDelta || event.detail) > 0)
scrEl.scrollLeft -= d;
else
scrEl.scrollLeft += d;
event.preventDefault();
return false;
};
if ("onmousewheel" in this.contentWindow.document)
this.contentWindow.document.onmousewheel = mouseWheelEvt;
else
this.contentWindow.document.body.addEventListener("DOMMouseScroll", mouseWheelEvt, true);
};
</script>
</body>
</html>
And iframecontent.html:
<!DOCTYPE html>
<html>
<head>
<meta charset=utf-8>
<title>iframe</title>
<style>
* { padding: 0; margin: 0; border: 0 }
#long { background: #ccc; height: 500px; width: 5000px }
</style>
</head>
<body>
<div id="long">long 5000px div</div>
</body>
</html>
I only tested this in Firefox 3.6.3 and Chromium 5.0.342.9, both running on Linux. To prevent errors in Chrome (about accessing iframes from a different domain or using a different protocol), you should upload these files or use a local test server (localhost).
One more side note: I highly doubt this will work in every (major) browser. At least it doesn't in (the highly standards compliant) Opera.
Update 2: On further testing the scrolling directions in Firefox and Chrome were opposite. I adjusted my code accordingly, using Mohammad's suggestions.
I also tested this in IE 7, but, although IE supports onmousewheel events, it didn't work properly. At this point I'm a little bored, so maybe I'll try to adapt the example to IE another time.
Horizontal Scrolling on React Component Using Vertical Mouse Wheel
Okay, so the issue seems to be that you only refer to the function event.preventDefault
rather than invoking it.
Adding some brackets at the end to invoke it should do the trick:event.preventDefault()
.
I however found this issue while looking for some simple code to use, so I will also leave the hook I made for this if others in the same situation:
import { useRef, useEffect } from "react";
export function useHorizontalScroll() {
const elRef = useRef();
useEffect(() => {
const el = elRef.current;
if (el) {
const onWheel = e => {
if (e.deltaY == 0) return;
e.preventDefault();
el.scrollTo({
left: el.scrollLeft + e.deltaY,
behavior: "smooth"
});
};
el.addEventListener("wheel", onWheel);
return () => el.removeEventListener("wheel", onWheel);
}
}, []);
return elRef;
}
Usage:
import React from "react";
import { useSideScroll } from "./useSideScroll";
export const SideScrollTest = () => {
const scrollRef = useHorizontalScroll();
return (
<div ref={scrollRef} style={{ width: 300, overflow: "auto" }}>
<div style={{ whiteSpace: "nowrap" }}>
I will definitely overflow due to the small width of my parent container
</div>
</div>
);
};
Note:
The scroll behavior "smooth" seems to be giving some trouble when trying to do continuous scrolling. This behavior can be omitted to have proper continuous scrolling, but it will look jerky.
As far as I know, there is no easy solution for this. I have however created a rather involved solution in my own project, so thought some people may appreciate that also: https://gist.github.com/TarVK/4cc89772e606e57f268d479605d7aded
Related Topics
What Is _Future_ in Python Used for and How/When to Use It, and How It Works
How to Read and Write Ini File with Python3
Could Pandas Use Column as Index
How Did Python Implement the Built-In Function Pow()
How to Compare String and Integer in Python
Databaseerror: Current Transaction Is Aborted, Commands Ignored Until End of Transaction Block
C and Python - Different Behaviour of the Modulo (%) Operation
Python Argparse Mutual Exclusive Group
Converting String to Int Using Try/Except in Python
Problem with Multi Threaded Python App and Socket Connections
Simple Argparse Example Wanted: 1 Argument, 3 Results
Python: Pandas Series - Why Use Loc
How to Account for Period (Am/Pm) Using Strftime
Pandas Split Column into Multiple Columns by Comma