I finally figured out how to prevent the tick labels from overlapping. The key was to re-implement the QwtAbstractScaleDraw::draw(QPainter *, const QPallette &) function and roll my own.
Once inside the draw function, I can calculate the size of the tick labels and determine if they are going to overlap. If they do, then I start deleting every other one in order so that they don't appear jumpy when panning. Here is my code.
Warning: I made a couple of presumptions in my code because I always just tick labels which are not rotated and always center aligned.
// Get the major tick values
QList<double> major_ticks
= scaleDiv
().
ticks(QwtScaleDiv::MajorTick);
QList<QRect> label_rects;
// Remove the unused ticks
for(i = major_ticks.count(); --i >= 0;)
{
if(!scaleDiv().contains(major_ticks[i]))
{
major_ticks.removeAt(i);
}
}
// Compute the rectangles of the major ticks
for (i = 0; i < major_ticks.size(); i++)
{
QRect bounds
= boundingLabelRect
(painter
->font
(), major_ticks
[i
]);
int half_padding = painter->font().pointSize() / 4;
if(orientation() == Qt::Horizontal)
{
bounds.adjust(-half_padding, 0, half_padding, 0);
}
else
{
bounds.adjust(0, -half_padding / 2, 0, half_padding / 2);
}
label_rects.append(bounds);
}
// Now remove the overlapping tick labels
bool overlap_found = false;
do
{
overlap_found = false;
for(i = 1; i < label_rects.size(); i++)
{
QRect last_rect
= label_rects.
at(i
-1);
QRect current_rect
= label_rects.
at(i
);
// Check if they overlap
if(current_rect.intersects(last_rect))
{
overlap_found = true;
break;
}
}
if(overlap_found)
{
// Now remove the next to last tick if the number is even
if((major_ticks.size() % 2) == 0)
{
// Remove the next to last tick
if(major_ticks.size() > 2)
{
label_rects.removeAt(major_ticks.size() - 2);
major_ticks.removeAt(major_ticks.size() - 2);
}
}
// Remove every other one starting at the second tick mark
for(i = (major_ticks.size() / 2) * 2 - 1; i >= 0; i -= 2)
{
label_rects.removeAt(i);
major_ticks.removeAt(i);
}
}
} while(overlap_found);
// Now draw the remaining tick labels
for (int i = 0; i < major_ticks.size(); i++)
{
drawLabel(painter, major_ticks[i]);
}
// Get the major tick values
QList<double> major_ticks = scaleDiv().ticks(QwtScaleDiv::MajorTick);
QList<QRect> label_rects;
// Remove the unused ticks
for(i = major_ticks.count(); --i >= 0;)
{
if(!scaleDiv().contains(major_ticks[i]))
{
major_ticks.removeAt(i);
}
}
// Compute the rectangles of the major ticks
for (i = 0; i < major_ticks.size(); i++)
{
QRect bounds = boundingLabelRect(painter->font(), major_ticks[i]);
int half_padding = painter->font().pointSize() / 4;
if(orientation() == Qt::Horizontal)
{
bounds.adjust(-half_padding, 0, half_padding, 0);
}
else
{
bounds.adjust(0, -half_padding / 2, 0, half_padding / 2);
}
label_rects.append(bounds);
}
// Now remove the overlapping tick labels
bool overlap_found = false;
do
{
overlap_found = false;
for(i = 1; i < label_rects.size(); i++)
{
QRect last_rect = label_rects.at(i-1);
QRect current_rect = label_rects.at(i);
// Check if they overlap
if(current_rect.intersects(last_rect))
{
overlap_found = true;
break;
}
}
if(overlap_found)
{
// Now remove the next to last tick if the number is even
if((major_ticks.size() % 2) == 0)
{
// Remove the next to last tick
if(major_ticks.size() > 2)
{
label_rects.removeAt(major_ticks.size() - 2);
major_ticks.removeAt(major_ticks.size() - 2);
}
}
// Remove every other one starting at the second tick mark
for(i = (major_ticks.size() / 2) * 2 - 1; i >= 0; i -= 2)
{
label_rects.removeAt(i);
major_ticks.removeAt(i);
}
}
} while(overlap_found);
// Now draw the remaining tick labels
for (int i = 0; i < major_ticks.size(); i++)
{
drawLabel(painter, major_ticks[i]);
}
To copy to clipboard, switch view to plain text mode
I hope that someone else can benefit from my struggles.
If you have any improvements on my code, please send them on.
Bookmarks