Дело тут вот в чём. События рисования могут проскакивать когда угодно по любому чиху, и потому механизмы перерисовки надо делать такие, что когда угодно этот paintEvent() проскочит — изображение в окне будет корректно восстановлено.
Например:
enum class Shape { NONE, LINE, ELLIPSE, RECTANGLE };
... в форме...
Shape shareToDraw = Shape::NONE;
…соответственно в коде нажатия кнопок устанавливаем эту shapeToDraw,
а paintEvent реагирует на неё.
У вас же, как только paintEvent() повторно проскочит, ни одно событие не будет отмечено, и он ничего не сделает. А ведь он может дважды проскочить, чтобы нарисовать непрямоугольную область. Или если оконный менеджер что-то попросил.