Browse Source

Added some notes and an assertion to Component::grabKeyboardFocus(), to help people avoid a common mistake, which is trying to grab the focus of not-yet-visible components.

tags/2021-05-28
jules 8 years ago
parent
commit
e253b8bea1
3 changed files with 49 additions and 37 deletions
  1. +1
    -1
      extras/Projucer/Source/Project/jucer_ProjectContentComponent.cpp
  2. +43
    -36
      modules/juce_gui_basics/components/juce_Component.cpp
  3. +5
    -0
      modules/juce_gui_basics/components/juce_Component.h

+ 1
- 1
extras/Projucer/Source/Project/jucer_ProjectContentComponent.cpp View File

@@ -728,7 +728,7 @@ bool ProjectContentComponent::showDocument (OpenDocumentManager::Document* doc,
bool opened = setEditorComponent (doc->createEditor(), doc); bool opened = setEditorComponent (doc->createEditor(), doc);
if (opened && grabFocus)
if (opened && grabFocus && isShowing())
contentView->grabKeyboardFocus(); contentView->grabKeyboardFocus();
return opened; return opened;


+ 43
- 36
modules/juce_gui_basics/components/juce_Component.cpp View File

@@ -69,7 +69,7 @@ public:
if (checker.shouldBailOut()) if (checker.shouldBailOut())
return; return;
if (MouseListenerList* const list = comp.mouseListeners)
if (auto* list = comp.mouseListeners.get())
{ {
for (int i = list->listeners.size(); --i >= 0;) for (int i = list->listeners.size(); --i >= 0;)
{ {
@@ -84,7 +84,7 @@ public:
for (Component* p = comp.parentComponent; p != nullptr; p = p->parentComponent) for (Component* p = comp.parentComponent; p != nullptr; p = p->parentComponent)
{ {
MouseListenerList* const list = p->mouseListeners;
auto* list = p->mouseListeners.get();
if (list != nullptr && list->numDeepMouseListeners > 0) if (list != nullptr && list->numDeepMouseListeners > 0)
{ {
@@ -106,7 +106,7 @@ public:
static void sendWheelEvent (Component& comp, Component::BailOutChecker& checker, static void sendWheelEvent (Component& comp, Component::BailOutChecker& checker,
const MouseEvent& e, const MouseWheelDetails& wheel) const MouseEvent& e, const MouseWheelDetails& wheel)
{ {
if (MouseListenerList* const list = comp.mouseListeners)
if (auto* list = comp.mouseListeners.get())
{ {
for (int i = list->listeners.size(); --i >= 0;) for (int i = list->listeners.size(); --i >= 0;)
{ {
@@ -144,9 +144,8 @@ private:
Array<MouseListener*> listeners; Array<MouseListener*> listeners;
int numDeepMouseListeners; int numDeepMouseListeners;
class BailOutChecker2
struct BailOutChecker2
{ {
public:
BailOutChecker2 (Component::BailOutChecker& boc, Component* const comp) BailOutChecker2 (Component::BailOutChecker& boc, Component* const comp)
: checker (boc), safePointer (comp) : checker (boc), safePointer (comp)
{ {
@@ -361,7 +360,7 @@ struct Component::ComponentHelpers
template <typename PointOrRect> template <typename PointOrRect>
static PointOrRect convertFromDistantParentSpace (const Component* parent, const Component& target, const PointOrRect& coordInParent) static PointOrRect convertFromDistantParentSpace (const Component* parent, const Component& target, const PointOrRect& coordInParent)
{ {
const Component* const directParent = target.getParentComponent();
auto* directParent = target.getParentComponent();
jassert (directParent != nullptr); jassert (directParent != nullptr);
if (directParent == parent) if (directParent == parent)
@@ -389,7 +388,7 @@ struct Component::ComponentHelpers
if (target == nullptr) if (target == nullptr)
return p; return p;
const Component* const topLevelComp = target->getTopLevelComponent();
auto* topLevelComp = target->getTopLevelComponent();
p = convertFromParentSpace (*topLevelComp, p); p = convertFromParentSpace (*topLevelComp, p);
@@ -504,7 +503,7 @@ void Component::setName (const String& name)
componentName = name; componentName = name;
if (flags.hasHeavyweightPeerFlag) if (flags.hasHeavyweightPeerFlag)
if (ComponentPeer* const peer = getPeer())
if (auto* peer = getPeer())
peer->setTitle (name); peer->setTitle (name);
BailOutChecker checker (this); BailOutChecker checker (this);
@@ -554,7 +553,7 @@ void Component::setVisible (bool shouldBeVisible)
if (safePointer != nullptr && flags.hasHeavyweightPeerFlag) if (safePointer != nullptr && flags.hasHeavyweightPeerFlag)
{ {
if (ComponentPeer* const peer = getPeer())
if (auto* peer = getPeer())
{ {
peer->setVisible (shouldBeVisible); peer->setVisible (shouldBeVisible);
internalHierarchyChanged(); internalHierarchyChanged();
@@ -583,7 +582,7 @@ bool Component::isShowing() const
if (parentComponent != nullptr) if (parentComponent != nullptr)
return parentComponent->isShowing(); return parentComponent->isShowing();
if (const ComponentPeer* const peer = getPeer())
if (auto* peer = getPeer())
return ! peer->isMinimised(); return ! peer->isMinimised();
return false; return false;
@@ -592,7 +591,7 @@ bool Component::isShowing() const
//============================================================================== //==============================================================================
void* Component::getWindowHandle() const void* Component::getWindowHandle() const
{ {
if (const ComponentPeer* const peer = getPeer())
if (auto* peer = getPeer())
return peer->getNativeHandle(); return peer->getNativeHandle();
return nullptr; return nullptr;
@@ -865,7 +864,7 @@ void Component::reorderChildInternal (const int sourceIndex, const int destIndex
{ {
if (sourceIndex != destIndex) if (sourceIndex != destIndex)
{ {
Component* const c = childComponentList.getUnchecked (sourceIndex);
auto* c = childComponentList.getUnchecked (sourceIndex);
jassert (c != nullptr); jassert (c != nullptr);
c->repaintParent(); c->repaintParent();
@@ -884,7 +883,7 @@ void Component::toFront (const bool setAsForeground)
if (flags.hasHeavyweightPeerFlag) if (flags.hasHeavyweightPeerFlag)
{ {
if (ComponentPeer* const peer = getPeer())
if (auto* peer = getPeer())
{ {
peer->toFront (setAsForeground); peer->toFront (setAsForeground);
@@ -919,7 +918,9 @@ void Component::toFront (const bool setAsForeground)
if (setAsForeground) if (setAsForeground)
{ {
internalBroughtToFront(); internalBroughtToFront();
grabKeyboardFocus();
if (isShowing())
grabKeyboardFocus();
} }
} }
} }
@@ -955,8 +956,8 @@ void Component::toBehind (Component* const other)
if (other->isOnDesktop()) if (other->isOnDesktop())
{ {
ComponentPeer* const us = getPeer();
ComponentPeer* const them = other->getPeer();
auto* us = getPeer();
auto* them = other->getPeer();
jassert (us != nullptr && them != nullptr); jassert (us != nullptr && them != nullptr);
if (us != nullptr && them != nullptr) if (us != nullptr && them != nullptr)
@@ -1004,7 +1005,7 @@ void Component::setAlwaysOnTop (const bool shouldStayOnTop)
if (isOnDesktop()) if (isOnDesktop())
{ {
if (ComponentPeer* const peer = getPeer())
if (auto* peer = getPeer())
{ {
if (! peer->setAlwaysOnTop (shouldStayOnTop)) if (! peer->setAlwaysOnTop (shouldStayOnTop))
{ {
@@ -1153,7 +1154,7 @@ void Component::setBounds (const int x, const int y, int w, int h)
flags.isResizeCallbackPending = wasResized; flags.isResizeCallbackPending = wasResized;
if (flags.hasHeavyweightPeerFlag) if (flags.hasHeavyweightPeerFlag)
if (ComponentPeer* const peer = getPeer())
if (auto* peer = getPeer())
peer->updateBounds(); peer->updateBounds();
sendMovedResizedMessagesIfPending(); sendMovedResizedMessagesIfPending();
@@ -1413,7 +1414,7 @@ bool Component::contains (Point<int> point)
return parentComponent->contains (ComponentHelpers::convertToParentSpace (*this, point)); return parentComponent->contains (ComponentHelpers::convertToParentSpace (*this, point));
if (flags.hasHeavyweightPeerFlag) if (flags.hasHeavyweightPeerFlag)
if (const ComponentPeer* const peer = getPeer())
if (auto* peer = getPeer())
return peer->contains (ComponentHelpers::localPositionToRawPeerPos (*this, point), true); return peer->contains (ComponentHelpers::localPositionToRawPeerPos (*this, point), true);
} }
@@ -1425,8 +1426,8 @@ bool Component::reallyContains (Point<int> point, const bool returnTrueIfWithinA
if (! contains (point)) if (! contains (point))
return false; return false;
Component* const top = getTopLevelComponent();
const Component* const compAtPosition = top->getComponentAt (top->getLocalPoint (this, point));
auto* top = getTopLevelComponent();
auto* compAtPosition = top->getComponentAt (top->getLocalPoint (this, point));
return (compAtPosition == this) || (returnTrueIfWithinAChild && isParentOf (compAtPosition)); return (compAtPosition == this) || (returnTrueIfWithinAChild && isParentOf (compAtPosition));
} }
@@ -1538,7 +1539,7 @@ Component* Component::removeChildComponent (const int index, bool sendParentEven
// thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe. // thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe.
ASSERT_MESSAGE_MANAGER_IS_LOCKED_OR_OFFSCREEN ASSERT_MESSAGE_MANAGER_IS_LOCKED_OR_OFFSCREEN
Component* const child = childComponentList [index];
auto* child = childComponentList [index];
if (child != nullptr) if (child != nullptr)
{ {
@@ -1619,7 +1620,7 @@ Component* Component::findChildWithID (StringRef targetID) const noexcept
{ {
for (int i = childComponentList.size(); --i >= 0;) for (int i = childComponentList.size(); --i >= 0;)
{ {
Component* const c = childComponentList.getUnchecked(i);
auto* c = childComponentList.getUnchecked(i);
if (c->componentID == targetID) if (c->componentID == targetID)
return c; return c;
} }
@@ -1799,7 +1800,7 @@ bool Component::isCurrentlyModal (bool onlyConsiderForemostModalComponent) const
bool Component::isCurrentlyBlockedByAnotherModalComponent() const bool Component::isCurrentlyBlockedByAnotherModalComponent() const
{ {
Component* const mc = getCurrentlyModalComponent();
auto* mc = getCurrentlyModalComponent();
return ! (mc == nullptr || mc == this || mc->isParentOf (this) return ! (mc == nullptr || mc == this || mc->isParentOf (this)
|| mc->canModalEventBeSentToComponent (this)); || mc->canModalEventBeSentToComponent (this));
@@ -1875,7 +1876,7 @@ void Component::alphaChanged()
{ {
if (flags.hasHeavyweightPeerFlag) if (flags.hasHeavyweightPeerFlag)
{ {
if (ComponentPeer* const peer = getPeer())
if (auto* peer = getPeer())
peer->setAlpha (getAlpha()); peer->setAlpha (getAlpha());
} }
else else
@@ -1929,7 +1930,7 @@ void Component::internalRepaintUnchecked (Rectangle<int> area, const bool isEnti
// thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe. // thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe.
ASSERT_MESSAGE_MANAGER_IS_LOCKED ASSERT_MESSAGE_MANAGER_IS_LOCKED
if (ComponentPeer* const peer = getPeer())
if (auto* peer = getPeer())
{ {
// Tweak the scaling so that the component's integer size exactly aligns with the peer's scaled size // Tweak the scaling so that the component's integer size exactly aligns with the peer's scaled size
const Rectangle<int> peerBounds (peer->getBounds()); const Rectangle<int> peerBounds (peer->getBounds());
@@ -2327,7 +2328,7 @@ bool Component::canModalEventBeSentToComponent (const Component*)
void Component::internalModalInputAttempt() void Component::internalModalInputAttempt()
{ {
if (Component* const current = getCurrentlyModalComponent())
if (auto* current = getCurrentlyModalComponent())
current->inputAttemptWhenModal(); current->inputAttemptWhenModal();
} }
@@ -2341,7 +2342,7 @@ void Component::postCommandMessage (const int commandId)
void messageCallback() override void messageCallback() override
{ {
if (Component* c = target.get())
if (auto* c = target.get())
c->handleCommandMessage (commandId); c->handleCommandMessage (commandId);
} }
@@ -2684,7 +2685,7 @@ void Component::internalBroughtToFront()
// When brought to the front and there's a modal component blocking this one, // When brought to the front and there's a modal component blocking this one,
// we need to bring the modal one to the front instead.. // we need to bring the modal one to the front instead..
if (Component* const cm = getCurrentlyModalComponent())
if (auto* cm = getCurrentlyModalComponent())
if (cm->getTopLevelComponent() != getTopLevelComponent()) if (cm->getTopLevelComponent() != getTopLevelComponent())
ModalComponentManager::getInstance()->bringModalComponentsToFront (false); // very important that this is false, otherwise in Windows, ModalComponentManager::getInstance()->bringModalComponentsToFront (false); // very important that this is false, otherwise in Windows,
// non-front components can't get focus when another modal comp is // non-front components can't get focus when another modal comp is
@@ -2793,7 +2794,7 @@ void Component::takeKeyboardFocus (const FocusChangeType cause)
if (currentlyFocusedComponent != this) if (currentlyFocusedComponent != this)
{ {
// get the focus onto our desktop window // get the focus onto our desktop window
if (ComponentPeer* const peer = getPeer())
if (auto* peer = getPeer())
{ {
const WeakReference<Component> safePointer (this); const WeakReference<Component> safePointer (this);
peer->grabFocus(); peer->grabFocus();
@@ -2839,7 +2840,7 @@ void Component::grabFocusInternal (const FocusChangeType cause, const bool canTr
if (traverser != nullptr) if (traverser != nullptr)
{ {
Component* const defaultComp = traverser->getDefaultComponent (this);
auto* defaultComp = traverser->getDefaultComponent (this);
traverser = nullptr; traverser = nullptr;
if (defaultComp != nullptr) if (defaultComp != nullptr)
@@ -2867,6 +2868,12 @@ void Component::grabKeyboardFocus()
ASSERT_MESSAGE_MANAGER_IS_LOCKED ASSERT_MESSAGE_MANAGER_IS_LOCKED
grabFocusInternal (focusChangedDirectly, true); grabFocusInternal (focusChangedDirectly, true);
// A component can only be focused when it's actually on the screen!
// If this fails then you're probably trying to grab the focus before you've
// added the component to a parent or made it visible. Or maybe one of its parent
// components isn't yet visible.
jassert (isShowing() || isOnDesktop());
} }
void Component::moveKeyboardFocusToSibling (const bool moveToNext) void Component::moveKeyboardFocusToSibling (const bool moveToNext)
@@ -2881,8 +2888,8 @@ void Component::moveKeyboardFocusToSibling (const bool moveToNext)
if (traverser != nullptr) if (traverser != nullptr)
{ {
Component* const nextComp = moveToNext ? traverser->getNextComponent (this)
: traverser->getPreviousComponent (this);
auto* nextComp = moveToNext ? traverser->getNextComponent (this)
: traverser->getPreviousComponent (this);
traverser = nullptr; traverser = nullptr;
if (nextComp != nullptr) if (nextComp != nullptr)
@@ -2918,13 +2925,13 @@ Component* JUCE_CALLTYPE Component::getCurrentlyFocusedComponent() noexcept
void JUCE_CALLTYPE Component::unfocusAllComponents() void JUCE_CALLTYPE Component::unfocusAllComponents()
{ {
if (Component* c = getCurrentlyFocusedComponent())
if (auto* c = getCurrentlyFocusedComponent())
c->giveAwayFocus (true); c->giveAwayFocus (true);
} }
void Component::giveAwayFocus (const bool sendFocusLossEvent) void Component::giveAwayFocus (const bool sendFocusLossEvent)
{ {
Component* const componentLosingFocus = currentlyFocusedComponent;
auto* componentLosingFocus = currentlyFocusedComponent;
currentlyFocusedComponent = nullptr; currentlyFocusedComponent = nullptr;
if (sendFocusLossEvent && componentLosingFocus != nullptr) if (sendFocusLossEvent && componentLosingFocus != nullptr)
@@ -2966,7 +2973,7 @@ void Component::sendEnablementChangeMessage()
for (int i = getNumChildComponents(); --i >= 0;) for (int i = getNumChildComponents(); --i >= 0;)
{ {
if (Component* const c = getChildComponent (i))
if (auto* c = getChildComponent (i))
{ {
c->sendEnablementChangeMessage(); c->sendEnablementChangeMessage();


+ 5
- 0
modules/juce_gui_basics/components/juce_Component.h View File

@@ -1208,6 +1208,11 @@ public:
parent instead, unless it's a top-level component without a parent, parent instead, unless it's a top-level component without a parent,
in which case it just takes the focus itself. in which case it just takes the focus itself.
Important note! It's obviously not possible for a component to be focused
unless it's actually visible, on-screen, and inside a window that is also
visible. So there's no point trying to call this in the component's own
constructor or before all of its parent hierarchy has been fully instantiated.
@see setWantsKeyboardFocus, getWantsKeyboardFocus, hasKeyboardFocus, @see setWantsKeyboardFocus, getWantsKeyboardFocus, hasKeyboardFocus,
getCurrentlyFocusedComponent, focusGained, focusLost, getCurrentlyFocusedComponent, focusGained, focusLost,
keyPressed, keyStateChanged keyPressed, keyStateChanged


Loading…
Cancel
Save